中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Python中的垃圾回收機制實例

發布時間:2020-06-28 15:56:12 來源:億速云 閱讀:141 作者:清晨 欄目:編程語言

這篇文章將為大家詳細講解有關Python中的垃圾回收機制實例,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

1. 引用計數器

1.1 環狀雙向鏈表 refchain

Python中的垃圾回收機制實例

在python程序中創建的任何對象都會放在refchain鏈表中。

#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;
name = "阿瑋"
age = 18
hobby = ["健身", "美女"]
內部會創建一些數據 [ 上一個對象、下一個對象、類型、引用個數 ]
name = "阿瑋"
new = name      # 引用個數變成2
內部會創建一些數據 [ 上一個對象、下一個對象、類型、引用個數、val=18 ]
age = 18
內部會創建一些數據 [ 上一個對象、下一個對象、類型、引用個數、items=元素、元素個數 ]
hobby = ["健身", "美女"]
#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;

在C源碼中如何體現每個對象中都有的相同的值:PyObject結構體(4個值)。

有多個元素組成的對象:PyObject結構體(4個值)+ ob_size = PyVarObject。

1.2 類型封裝結構體

float類型

typedef struct {
    PyObject_HEAD;
    double ob_fval;
};
data = 3.14;
內部會創建:
    _ob_next = refchain中的下一個對象
    _ob_prev = refchain中的上一個對象
    ob_refcnt = 1
    ob_type = float
    ob_fval = 3.14

int類型

struct _longobect {
    PyObject_VAR_HEAD;
    digit ob_dit[1];
};
/* Long (arbitrary precision) integer object interface */
typedef struct _longobject PyLongObject; /* Revealed in longintrepr.h */

list類型

typedef struct {
    PyObject_VAR_HEAD;
    PyObject ** ob_item;
    Py_ssize_t allocated;
} PyListObject;

tuple類型

typedef struct {
    PyObject_VAR_HEAD;
    PyObject *ob_item[1];
} PyTupleObject;

dict類型

typedef struct {
    PyObject_HEAD;
    Py_ssize_t ma_used;
    PyDictKeyObject *ma_keys;
    PyObject **ma_values;
} PyDictObject;

1.3 引用計數器

v1 = 3.14
v2 = 999
v3 = (1,2,3)

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

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

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

引用

a = 99999
b = a
# 此時 99999 這個對象引用計數器的值為2
'''
下面情況會導致引用計數器+1:
    1.對象被創建,如 a = 2
    2.對象被引用,如 b = a
    3.對象被作為參數,傳入到一個函數中
    4.對象作為一個元素,存儲在容器中
可以通過sys包中的getrefcount()來獲取一個名稱所引用的對象當前的引用計數器的值(注意這里getrefcount()本身會使得引用計數器+1)
'''

刪除引用

a = 99999
b = a
# b變量刪除,b對應對象的引用計數器-1
def b
# a變量刪除,a對應對象的引用計數器-1
'''
下面情況會導致引用計數器-1:
    1.變量被顯示銷毀 del
    2.變量被賦予新的對象
    3.一個對象離開它的作用域
    4.對象所在的容器被銷毀或從容器中刪除對象
'''
# 當一個對象的引用計數器為0時,意味著沒有人再使用這個對象了,這個對象就是垃圾,垃圾回收。
# 回收:1.對象從rechain鏈表移出。2.將對象銷毀,內存歸還。

Python中的垃圾回收機制實例

1.4 循環引用問題

Python中的垃圾回收機制實例

由于 v1 指向的對象引用了 v2,v2 指向的對象也引用了 v1,當將 v1、v2 兩個變量刪除時,雖然引用計數器會減1,但是兩個對象間還存在循環引用,而此時已經沒有變量能去指向它們,這兩個對象就會在內存中常駐無法處理。

2. 標記清除

目的:為了解決引用計數器循環引用的問題。

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

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

2.1 標記階段

遍歷所有對象,如果是可達的(reachable),也就是還有對象引用它,那么就將該對象標記為可達

該階段從某個對象開始掃描(而不是從變量),如果變量A引用了變量B,則將變量B的引用計數器-1(指的是gc_ref),然后掃描變量B

如圖所示,link1、link2、link3形成了一個引用環,link4自引用。從link1開始掃描,link1引用了link2,則link2的gc_ref-1,接著掃描link2…

像這也將鏈表中所有對象考察一遍后,兩個鏈表中的對象ref_count和gc_ref,這一步操作就相當于解除了循環引用對引用計數器的影響

如果gc_ref為0,則將對象標記為 GC_TENTATIVELY_UNREACHABLE,并且被移至”Unreachable“鏈表中,如下圖link3、link4(我覺得link2應該也是)

如果gc_ref不為0,那么這個對象會被標記為可達的GC_REACHABLE,同時當gc發現有一個節點是可達的,那么它會遞歸式的從該節點觸發將所有可達的節點標記為GC_REACHABLE,這樣把link2、link3救回來

2.2 清除階段

將被標記成 GC_UNREACHABLE 的對象銷毀,內存歸還(也就是Unreachable鏈表中的對象)

2.3 標記清除的問題

在標記清除算法開始后,會暫停整個應用程序,等待標記清除結束后才會恢復應用的運行,且對循環引用的掃描代價大,每次掃描耗時可能很久

3. 分代回收

Python中的垃圾回收機制實例

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

0代:0代中對象個數達到700個掃描一次

1代:0代掃描10次,則1代掃描一次

2代:1代掃描10次,則2代掃描一次

4. 小結

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

但是,在python中對于那些可以有多個元素組成的對象可能會存在循環引用的問題,為了解決這個問題,python又引入了標記清除和分代回收,在其內部維護了4個鏈表,分別為:

refchain

2代

1代

0代

在源碼內部,當達到各自的閾值時,就會觸發掃描鏈表進行標記清除的動作(有循環引用則各自-1)。But,源碼內部在上述流程中提出了優化機制。


關于Python中的垃圾回收機制實例就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

岳西县| 阿克| 文昌市| 威海市| 苏尼特左旗| 清丰县| 英吉沙县| 九台市| 日照市| 长垣县| 彭泽县| 丰城市| 玛沁县| 濮阳县| 鄯善县| 大竹县| 永修县| 茂名市| 望都县| 鄂温| 抚顺市| 弥渡县| 康平县| 嘉禾县| 安岳县| 乐亭县| 台江县| 长治县| 龙泉市| 昭平县| 乡城县| 沙湾县| 武乡县| 靖州| 临潭县| 林西县| 松溪县| 获嘉县| 饶河县| 石景山区| 阜南县|