久久久精品一区ed2k-女人被男人叉到高潮的视频-中文字幕乱码一区久久麻豆樱花-俄罗斯熟妇真实视频

Python中的垃圾回收機(jī)制實(shí)例

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

創(chuàng)新互聯(lián)專注于企業(yè)營銷型網(wǎng)站建設(shè)、網(wǎng)站重做改版、隆子網(wǎng)站定制設(shè)計(jì)、自適應(yīng)品牌網(wǎng)站建設(shè)、html5、商城網(wǎng)站制作、集團(tuán)公司官網(wǎng)建設(shè)、成都外貿(mào)網(wǎng)站建設(shè)公司、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計(jì)等建站業(yè)務(wù),價(jià)格優(yōu)惠性價(jià)比高,為隆子等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。

1. 引用計(jì)數(shù)器

1.1 環(huán)狀雙向鏈表 refchain

Python中的垃圾回收機(jī)制實(shí)例

在python程序中創(chuàng)建的任何對象都會放在refchain鏈表中。

#define PyObject_HEAD       PyObject ob_base;
#define PyObject_VAR_HEAD       PyVarObject ob_base;
// 宏定義,包含 上一個(gè)、下一個(gè),用于構(gòu)造雙向鏈表用。(放到refchain鏈表中時(shí)要用到)
#define _PyObject_HEAD_EXTRA            \
    struct _object *_ob_next;           \
    struct _object *_ob_prev;
name = "阿瑋"
age = 18
hobby = ["健身", "美女"]
內(nèi)部會創(chuàng)建一些數(shù)據(jù) [ 上一個(gè)對象、下一個(gè)對象、類型、引用個(gè)數(shù) ]
name = "阿瑋"
new = name      # 引用個(gè)數(shù)變成2
內(nèi)部會創(chuàng)建一些數(shù)據(jù) [ 上一個(gè)對象、下一個(gè)對象、類型、引用個(gè)數(shù)、val=18 ]
age = 18
內(nèi)部會創(chuàng)建一些數(shù)據(jù) [ 上一個(gè)對象、下一個(gè)對象、類型、引用個(gè)數(shù)、items=元素、元素個(gè)數(shù) ]
hobby = ["健身", "美女"]
#define PyObject_HEAD       PyObject ob_base;
#define PyObject_VAR_HEAD       PyVarObject ob_base;
// 宏定義,包含 上一個(gè)、下一個(gè),用于構(gòu)造雙向鏈表用。(放到refchain鏈表中時(shí)要用到)
#define _PyObject_HEAD_EXTRA            \
    struct _object *_ob_next;           \
    struct _object *_ob_prev;
typedef struct _object {
    _PyObject_HEAD_EXTRA;   // 用于構(gòu)造雙向鏈表
    Py_ssize_t ob_refcnt;   // 引用計(jì)數(shù)器
    struct _typeobject *ob_type;    // 數(shù)據(jù)類型
} PyObject;
typedef struct {
    PyObject ob_base;       // PyObject對象
    Py_ssize_t ob_size;     // Number of items in variable part,即:元素個(gè)數(shù)
} PyVarObject;

在C源碼中如何體現(xiàn)每個(gè)對象中都有的相同的值:PyObject結(jié)構(gòu)體(4個(gè)值)。

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

1.2 類型封裝結(jié)構(gòu)體

float類型

typedef struct {
    PyObject_HEAD;
    double ob_fval;
};
data = 3.14;
內(nèi)部會創(chuàng)建:
    _ob_next = refchain中的下一個(gè)對象
    _ob_prev = refchain中的上一個(gè)對象
    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 引用計(jì)數(shù)器

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

當(dāng)python程序運(yùn)行時(shí),會根據(jù)數(shù)據(jù)類型的不同找到其結(jié)構(gòu)體,根據(jù)結(jié)構(gòu)體中的字段來進(jìn)行創(chuàng)建相關(guān)的數(shù)據(jù),然后將對象添加到refchain雙向鏈表中。

在C源碼中有兩個(gè)關(guān)鍵的結(jié)構(gòu)體:PyObject、PyVarObject。

每個(gè)對象中有 ob_refcnt 就是引用計(jì)數(shù)器,值默認(rèn)為1,當(dāng)有其他變量引用這個(gè)對象時(shí),引用計(jì)數(shù)器就會發(fā)生變化。

引用

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

刪除引用

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

Python中的垃圾回收機(jī)制實(shí)例

1.4 循環(huán)引用問題

Python中的垃圾回收機(jī)制實(shí)例

由于 v1 指向的對象引用了 v2,v2 指向的對象也引用了 v1,當(dāng)將 v1、v2 兩個(gè)變量刪除時(shí),雖然引用計(jì)數(shù)器會減1,但是兩個(gè)對象間還存在循環(huán)引用,而此時(shí)已經(jīng)沒有變量能去指向它們,這兩個(gè)對象就會在內(nèi)存中常駐無法處理。

2. 標(biāo)記清除

目的:為了解決引用計(jì)數(shù)器循環(huán)引用的問題。

實(shí)現(xiàn):在python的底層再維護(hù)一個(gè)鏈表,鏈表中專門放哪些可能存在循環(huán)應(yīng)用的對象(容器類對象:list、tuple、dict、set)。

在Python內(nèi)部某種情況下觸發(fā),會去掃描可能存在循環(huán)引用的鏈表中的每個(gè)元素,檢查是否有循環(huán)引用,如果有則讓雙方的引用計(jì)數(shù)器-1;如果是0則垃圾回收。

2.1 標(biāo)記階段

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

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

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

像這也將鏈表中所有對象考察一遍后,兩個(gè)鏈表中的對象ref_count和gc_ref,這一步操作就相當(dāng)于解除了循環(huán)引用對引用計(jì)數(shù)器的影響

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

如果gc_ref不為0,那么這個(gè)對象會被標(biāo)記為可達(dá)的GC_REACHABLE,同時(shí)當(dāng)gc發(fā)現(xiàn)有一個(gè)節(jié)點(diǎn)是可達(dá)的,那么它會遞歸式的從該節(jié)點(diǎn)觸發(fā)將所有可達(dá)的節(jié)點(diǎn)標(biāo)記為GC_REACHABLE,這樣把link2、link3救回來

2.2 清除階段

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

2.3 標(biāo)記清除的問題

在標(biāo)記清除算法開始后,會暫停整個(gè)應(yīng)用程序,等待標(biāo)記清除結(jié)束后才會恢復(fù)應(yīng)用的運(yùn)行,且對循環(huán)引用的掃描代價(jià)大,每次掃描耗時(shí)可能很久

3. 分代回收

Python中的垃圾回收機(jī)制實(shí)例

將可能存在循環(huán)引用的對象維護(hù)成3個(gè)鏈表:

0代:0代中對象個(gè)數(shù)達(dá)到700個(gè)掃描一次

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

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

4. 小結(jié)

在python中維護(hù)了一個(gè)refchain的雙向環(huán)狀鏈表,這個(gè)鏈表中存儲程序創(chuàng)建的所有對象,每種類型的對象都有一個(gè)ob_refcnt引用計(jì)數(shù)器的值,當(dāng)引用計(jì)數(shù)器變?yōu)?時(shí)會進(jìn)行垃圾回收(對象銷毀、refchain中移出)。

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

refchain

2代

1代

0代

在源碼內(nèi)部,當(dāng)達(dá)到各自的閾值時(shí),就會觸發(fā)掃描鏈表進(jìn)行標(biāo)記清除的動(dòng)作(有循環(huán)引用則各自-1)。But,源碼內(nèi)部在上述流程中提出了優(yōu)化機(jī)制。

關(guān)于Python中的垃圾回收機(jī)制實(shí)例就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。

網(wǎng)頁名稱:Python中的垃圾回收機(jī)制實(shí)例
網(wǎng)頁網(wǎng)址:http://sd-ha.com/article6/gcjeog.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供域名注冊、軟件開發(fā)、外貿(mào)建站、Google、微信小程序、網(wǎng)站導(dǎo)航

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

綿陽服務(wù)器托管