日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

Python 的垃圾回收回收机制(源码)

發布時間:2024/7/23 python 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python 的垃圾回收回收机制(源码) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

python內存管理及垃圾回收

1. 引用計數器

1.1 環狀雙向連表 refchain

在python程序中創建的任何對象都會放在refchain鏈表中,并且可以通過這個對象訪問到上一個和下一個對象。

name = '張三' age = 18 hobby = ['美女','吃飯'] 內部會建立一些數據 -打包 C語言叫做結構體-> 【上一個對象、下一個對象、類型、引用個數】 name = "張三" # 創建一個對象開辟內存空間 new = name # new指向指向"張三"這塊內存,不會重新分配內存,引用計數+1內部會建立一些數據 【上一個對象、下一個對象、類型、引用個數、val=18】 age = 18 # int會添加具體值內部會建立一些數據 【上一個對象、下一個對象、類型、引用個數、items=元素、元素個數】 hobby = ['美女','吃飯'] # 列表會添加元素和元素個數

C語言源碼

  • 每個對象都有相同的值:PyObject 結構體 (4個值)。
  • 有多個元素組成的對象:PyObject 結構體 (4個值) + ob_size 。
#define PyObject_HEAD PyObject ob_base; #define PyObject_VAR_HEAD PyVarObject ob_base;// 宏定義,包含 上一個、下一個,用于構造雙向鏈表。(放到refchain鏈表中時會用到) #define _PyObject_HEAD_EXTRA \struct _object *_ob_next; \struct _object *_ob_prev;// 結構體 typedef struct _object {_PyObject_HEAD_EXTRA // 用于構造雙向鏈表Py_ssize_t ob_refcnt; // 引用計數器struct _typeobject *ob_type; // 數據類型 } PyObject;typedef struct {PyObject ob_base; // PyObject對象Py_ssize_t ob_size; /* Number of items in variable part,即:元素個數 */ } PyVarObject;

源碼解析,包含:

  • 2個結構體
    • PyObject,此結構體中包含3個元素。
      • _PyObject_HEAD_EXTRA,用于構造雙向鏈表。
      • ob_refcnt,引用計數器。
      • *ob_type,數據類型。
    • PyVarObject,次結構體中包含4個元素(ob_base中包含3個元素)
      • ob_base,PyObject結構體對象,即:包含PyObject結構體中的三個元素。
      • ob_size,內部元素個數。
  • 3個宏定義
    • PyObject_HEAD,代指PyObject結構體。
    • PyVarObject_HEAD,代指PyVarObject對象。
    • _PyObject_HEAD_EXTRA,代指前后指針,用于構造雙向隊列。

1.2 不同類型封裝的結構體

# float類型 data = 3.14內部會創建:_ob_next = refchain 中的上一個對象_ob_prev = refchain 中的下一個對象 ob_refcnt = 1 ob_type = floatob_fval = 3.14

C源碼:

typedef struct {PyObject_HEADdouble ob_fval; } PyFloatObject;

1.3 引用計數器

v1 = 3.14 v2 = 999 v3 = [1,2,3]

當python程序運行時,會根據數據類型的不同找到其對應的結構體,根據結構體中的字段進行創建相關的數據,然后將對象添加到refchain雙向鏈表中。

在C源碼中有兩個關鍵的結構體:PyObject、PyVarObject。

每個對象中有ob_refcnt 就是引用計數器,默認值為1,當有其他變量引用對象時,引用計數器就會發生變化。

  • 引用

    a = 999 b = a # 999 這個對象的引用計數器+1,為2
  • 刪除引用

    a = 999 b = a del b # b變量刪除,b對應的對象的引用計數器 -1 del a # a變量刪除,a對應的對象的引用計數器 -1 (a、b對應同一個對象)""" 當一個對象的引用計數器為0時,意味著沒有人可以使用這個對象了,這個對象就是垃圾,需要被回收 回收:1.對象從refchain鏈表中移除2.將對象銷毀,內存歸還系統"""

    1.5 循環引用

2. 標記清除

目的:為了解決引用計數器循環引用的不足。

實現:在python的底層 再維護一個鏈表,鏈表中專門放那些可能存在循環引用的對象 (list/tuple/dict/set)。

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-V9eqdYfm-1605967623655)(E:\07-notes\picture\57_解決循環引用圖.png)]

在python內部 某種情況下 觸發,會去掃描 可能存在循環引用的鏈表中的每一個元素,檢查是否有循環引用,如果有則雙方的引用計數器 -1,如果是 0 則垃圾回收。

問題:

  • 什么時候掃描?
  • 可能存在循環引用的鏈表掃描代價較大,每次掃描耗時久。

3. 分代回收

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-K55asNPj-1605967623657)(E:\07-notes\picture\58_分待回收圖
.png)]

將可能存在循環引用的對象維護成 3個鏈表:

  • 0代:0代中對象個數達到700個掃描一次;
  • 1代:0代掃描 10 次,則 1代掃描一次;
  • 2代:1代掃描10次,則 2 代掃描一次。

4. 小結

在python中維護了一個refchain的雙向環狀鏈表,這個鏈表中存儲程序中創建的所有對象,每種類型的對象都有一個 ob_refcnt 的引用計數器的值,對象被引用,則計數器的值 +1,引用被刪除則計數器的值 -1,最后引用計數的值為 0 時,會進行垃圾回收(對象銷毀、從refchain中移除),

但是,在python中對于那些可以有多個元素組成的對象可能會存在循環引用問題,為了解決這個問題python引入了 標記清除 ,在其內部再維護了一個鏈表,專門放那些可能存在循環引用的對象 (list/tuple/dict/set), 某種情況下 觸發,會去掃描 可能存在循環引用的鏈表中的每一個元素,檢查是否有循環引用,如果有則雙方的引用計數器 -1,如果是 0 則垃圾回收,

然而,又有一個新的問題產生,就是什么時候掃描?可能存在循環引用的鏈表掃描代價較大,每次掃描耗時久,所以又引入了 分代回收 ,將可能存在循環引用對象維護成 3 個鏈表,分別是 0代,1代,2代,所有可能存在循環引用的對象都存儲在 0代鏈表,當對象個數達到700個的時候掃描一次,是垃圾則回收,不是則移代 1代,依次類推,0代掃描10次,1代掃描一次,1代掃描10次,2代掃描1次。

e=5>分代回收 ,將可能存在循環引用對象維護成 3 個鏈表,分別是 0代,1代,2代,所有可能存在循環引用的對象都存儲在 0代鏈表,當對象個數達到700個的時候掃描一次,是垃圾則回收,不是則移代 1代,依次類推,0代掃描10次,1代掃描一次,1代掃描10次,2代掃描1次。

總結

以上是生活随笔為你收集整理的Python 的垃圾回收回收机制(源码)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。