真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Python垃圾回收機(jī)制的原理

本篇內(nèi)容介紹了“Python垃圾回收機(jī)制的原理”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

蛟河ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場(chǎng)景,ssl證書(shū)未來(lái)市場(chǎng)廣闊!成為創(chuàng)新互聯(lián)的ssl證書(shū)銷(xiāo)售渠道,可以享受市場(chǎng)價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:18980820575(備注:SSL證書(shū)合作)期待與您的合作!

引用計(jì)數(shù)器為主

標(biāo)記清除和分代回收為輔

+ 緩存機(jī)制

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

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

在python程序中創(chuàng)建的任何對(duì)象都會(huì)放在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)部會(huì)創(chuàng)建一些數(shù)據(jù) [ 上一個(gè)對(duì)象、下一個(gè)對(duì)象、類(lèi)型、引用個(gè)數(shù) ]

name = "阿瑋"

new = name # 引用個(gè)數(shù)變成2

內(nèi)部會(huì)創(chuàng)建一些數(shù)據(jù) [ 上一個(gè)對(duì)象、下一個(gè)對(duì)象、類(lèi)型、引用個(gè)數(shù)、val=18 ]

age = 18

內(nèi)部會(huì)創(chuàng)建一些數(shù)據(jù) [ 上一個(gè)對(duì)象、下一個(gè)對(duì)象、類(lèi)型、引用個(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ù)類(lèi)型

} PyObject;

typedef struct {

PyObject ob_base; // PyObject對(duì)象

Py_ssize_t ob_size; // Number of items in variable part,即:元素個(gè)數(shù)

} PyVarObject;

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

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

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

float類(lèi)型

typedef struct {

PyObject_HEAD;

double ob_fval;

};

data = 3.14;

內(nèi)部會(huì)創(chuàng)建:

_ob_next = refchain中的下一個(gè)對(duì)象

_ob_prev = refchain中的上一個(gè)對(duì)象

ob_refcnt = 1

ob_type = float

ob_fval = 3.14

int類(lèi)型

struct _longobect {

PyObject_VAR_HEAD;

digit ob_dit[1];

};

/* Long (arbitrary precision) integer object interface */

typedef struct _longobject PyLongObject; /* Revealed in longintrepr.h */

list類(lèi)型

typedef struct {

PyObject_VAR_HEAD;

PyObject ** ob_item;

Py_ssize_t allocated;

} PyListObject;

tuple類(lèi)型

typedef struct {

PyObject_VAR_HEAD;

PyObject *ob_item[1];

} PyTupleObject;

dict類(lèi)型

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í),會(huì)根據(jù)數(shù)據(jù)類(lèi)型的不同找到其結(jié)構(gòu)體,根據(jù)結(jié)構(gòu)體中的字段來(lái)進(jìn)行創(chuàng)建相關(guān)的數(shù)據(jù),然后將對(duì)象添加到refchain雙向鏈表中。

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

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

引用

a = 99999

b = a

# 此時(shí) 99999 這個(gè)對(duì)象引用計(jì)數(shù)器的值為2

'''

下面情況會(huì)導(dǎo)致引用計(jì)數(shù)器+1:

1.對(duì)象被創(chuàng)建,如 a = 2

2.對(duì)象被引用,如 b = a

3.對(duì)象被作為參數(shù),傳入到一個(gè)函數(shù)中

4.對(duì)象作為一個(gè)元素,存儲(chǔ)在容器中

可以通過(guò)sys包中的getrefcount()來(lái)獲取一個(gè)名稱所引用的對(duì)象當(dāng)前的引用計(jì)數(shù)器的值(注意這里getrefcount()本身會(huì)使得引用計(jì)數(shù)器+1)

'''

刪除引用

a = 99999

b = a

# b變量刪除,b對(duì)應(yīng)對(duì)象的引用計(jì)數(shù)器-1

def b

# a變量刪除,a對(duì)應(yīng)對(duì)象的引用計(jì)數(shù)器-1

'''

下面情況會(huì)導(dǎo)致引用計(jì)數(shù)器-1:

1.變量被顯示銷(xiāo)毀 del

2.變量被賦予新的對(duì)象

3.一個(gè)對(duì)象離開(kāi)它的作用域

4.對(duì)象所在的容器被銷(xiāo)毀或從容器中刪除對(duì)象

'''

# 當(dāng)一個(gè)對(duì)象的引用計(jì)數(shù)器為0時(shí),意味著沒(méi)有人再使用這個(gè)對(duì)象了,這個(gè)對(duì)象就是垃圾,垃圾回收。

# 回收:1.對(duì)象從rechain鏈表移出。2.將對(duì)象銷(xiāo)毀,內(nèi)存歸還。

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

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

2. 標(biāo)記清除

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

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

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

2.1 標(biāo)記階段

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

該階段從某個(gè)對(duì)象開(kāi)始掃描(而不是從變量),如果變量A引用了變量B,則將變量B的引用計(jì)數(shù)器-1(指的是gc_ref),然后掃描變量B鄭州人流手術(shù)醫(yī)院 http://wap.zyfuke.com/

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

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

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

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

2.2 清除階段

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

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

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

3. 分代回收

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

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

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

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

4. 小結(jié)

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

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

refchain

2代

1代

0代

在源碼內(nèi)部,當(dāng)達(dá)到各自的閾值時(shí),就會(huì)觸發(fā)掃描鏈表進(jìn)行標(biāo)記清除的動(dòng)作(有循環(huán)引用則各自-1)。

But,源碼內(nèi)部在上述流程中提出了優(yōu)化機(jī)制。

“Python垃圾回收機(jī)制的原理”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!


網(wǎng)站標(biāo)題:Python垃圾回收機(jī)制的原理
分享地址:http://weahome.cn/article/gcjhop.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部