垃圾回收機(jī)制
????垃圾回收機(jī)制(Garbage Collection:GC)基本是所有高級語言的標(biāo)準(zhǔn)配置之一了。在一定程度上,能優(yōu)化編程語言的數(shù)據(jù)處理效率和提高編程軟件開發(fā)軟件的安全性能。
????在 PYTHON 中的垃圾回收機(jī)制主要是以引用計數(shù)為主要手段,以標(biāo)記清除和分代回收機(jī)制作為輔助操作手段,完成對內(nèi)存中無效數(shù)據(jù)的自動管理操作的!
引用計數(shù)
????引用計數(shù)[Reference Counting:RC]是 PYTHON 中的垃圾回收機(jī)制的核心操作算法。該算法最早是 George E.Collins 在 1960 年首次提出的,并在大部分高級語言中沿用至今,是很多高級語言的垃圾回收核心算法之一
(1) 什么是引用計數(shù)
????引用計數(shù)算法的核心思想是:當(dāng)一個對象被創(chuàng)建或者拷貝時,引用計數(shù)就會+1,當(dāng)這個對象的多個引用變量,被銷毀一個時該對象的引用計數(shù)就會-1,如果一個對象的引用計數(shù)為 0 則表示該對象已經(jīng)不被引用,就可以讓垃圾回收機(jī)制進(jìn)行清除并釋放該對象占有的內(nèi)存空間了。
????引用計數(shù)算法的優(yōu)點(diǎn)是:操作簡單,實(shí)時性能優(yōu)秀,能在最短的時間獲得并運(yùn)算對象引用數(shù).
????引用計數(shù)算法的缺點(diǎn)是:為了維護(hù)每個對象的引用計數(shù)操作算法,PYTHON 必須提供和對象對等的內(nèi)存消耗來維護(hù)引用計數(shù),這樣就在無形中增加了內(nèi)存負(fù)擔(dān);同時引用計數(shù)對于循環(huán) 應(yīng)用/對象之間的互相引用,是無法進(jìn)行引用計數(shù)操作的,所以就會造成常駐內(nèi)存的情況。
(2) PYTHON 中的引用計數(shù)
????PYTHON是一個面向?qū)ο蟮娜躅愋驼Z言,所有的對象都是直接或者間接繼承自object類型, object 類型的核心其實(shí)就是一個結(jié)構(gòu)體對象。
typedef struct_object {
int ob.refcnt;
struct_typeobject *ob_type;
} PyObject;
????在這個結(jié)構(gòu)體中,ob_refcnt就是對象的引用計數(shù),當(dāng)對象被創(chuàng)建或者拷貝時該計數(shù)就會增加1,當(dāng)對象的引用變量被刪除時,該計數(shù)就會減少1,當(dāng)引用計數(shù)為0時,對象數(shù)據(jù)就會被回收釋放。在python中,可以通過下面的方式獲取一個對象的引用計數(shù):
import sys
sys.getrefcount(對象名)
代碼示例:

標(biāo)記清除
????PYTHON中的標(biāo)記清除機(jī)制主要是針對可能產(chǎn)生循環(huán)引用的對象進(jìn)行的檢測機(jī)制。在python中的基本不可變類型,如:PyIntObject,PyStringObject等對象的內(nèi)部不會內(nèi)聚其他對象的引用,所以不會產(chǎn)生循環(huán)引用,一般情況下循環(huán)引用總是發(fā)生在其他可變對象的內(nèi)部屬性中,如list,dict,class等等,使得該方法消耗的資源和程序中可變對象的數(shù)量息息相關(guān)!
????標(biāo)記清除算法核心思想:首先找到PYTHON中的一批根節(jié)點(diǎn)對象,如object對象,通過根節(jié)點(diǎn)對象可以找到他們指向的子節(jié)點(diǎn)對象,如果搜索過程中這個指向是從上往下的指向,那么表示這個對象是可達(dá)的,否則該對象是不可達(dá)的,可達(dá)部分的對象在程序中需要保留下來,不可達(dá)部分的對象在程序中是不需要保留的。
對于如下代碼:
class A:
pass
class B:
pass
a = A()
b = B()
a.bb = b
b.aa = a

如果代碼中執(zhí)行了
del a
del b
????我們會發(fā)現(xiàn),對象A()和對象B()依然有指向引用他們,如果是之前的引用計數(shù)方式明顯區(qū)分不了這樣的對象是否應(yīng)該刪除,但是標(biāo)記清楚的方式就可以標(biāo)記出來對象A()和對象B()是不可達(dá)對象,不需要保留,直接刪除即可!

分代回收
????PYTHON中的分代回收機(jī)制是一種通過空間換取時間效率的做法,PYTHON內(nèi)部處理機(jī)制定義了三個不同的鏈表數(shù)據(jù)結(jié)構(gòu)[第零代(年輕代),第1代(中年代),第2代(老年代)]。PYTHON為了提高執(zhí)行效率,將垃圾回收機(jī)制進(jìn)行了閾值限定,0代鏈表中的垃圾回收機(jī)制執(zhí)行最為密集,其次是1代,最后是2代。
????PYTHON定義的這三個鏈表,主要是針對我們在程序中創(chuàng)建的對象,首先會添加到0代鏈表:

????隨后0代鏈表數(shù)量達(dá)到一定的閾值之后,出發(fā)GC算法機(jī)制,對0代對象進(jìn)行符合規(guī)則的引用計數(shù)運(yùn)算,避免出現(xiàn)對象的延遲或過早釋放。

????最終,觸發(fā)GC機(jī)制將已經(jīng)沒有引用指向的對象進(jìn)行回收,并將有引用指向的對象移動到第1代對象鏈表中;第1代對象鏈表的對象,就是比第0代對象鏈表中的對象可能存活更久的對象,GC閾值更大,檢測頻率更慢,以提高程序執(zhí)行效率。

????以此類推,直到一部分對象存活在第2代對象鏈表中,對象周期較長的可能會跟程序的生命周期一樣。
備注:
弱代假說:程序中年輕的對象往往死的更快,年老的對象往往存活更久
垃圾回收處理
對PYTHON中的垃圾回收機(jī)制有了一定的了解之后,我們針對垃圾回收機(jī)制的代碼進(jìn)行測試。
PYTHON中的gc模塊提供了垃圾回收處理的各項(xiàng)功能機(jī)制,必須引入進(jìn)去才能使用:
模塊引入
import gc
設(shè)置 gc 的 debug 日志,一般為 gc.DEBUG_LEAK
gc.set_debug(flags)
顯式進(jìn)行垃圾回收處理,可以輸入?yún)?shù),參數(shù)表示回收的對象代數(shù),0 表示只檢查第 0 代對象,1 表示檢查第 0、1 代對象,2 表示檢查 0、1、2 代對象,如果不傳遞參數(shù),執(zhí)行 FULL COLLECT,也就是默認(rèn)傳遞 2
gc.collect([generation])
設(shè)置執(zhí)行垃圾回收機(jī)制的頻率
gc.set_threshold(threshold0 [,threshold2 [,threshold3]])
獲取程序?qū)ο笠玫挠嫈?shù)器
gc.get_count()
獲取程序自動執(zhí)行 GC 的引用計數(shù)閾值
gc.get_threshold()
以上是 PYTHON 中垃圾回收機(jī)制的基本操作,在程序開發(fā)過程中需要注意:
? 項(xiàng)目代碼中盡量避免循環(huán)引用
? 引入 gc 模塊,啟用 gc 模塊自動清理循環(huán)引用對象的機(jī)制
? 將需要長期使用的對象集中管理,減少 GC 資源消耗
? gc模塊處理不了重寫del方法導(dǎo)致的循環(huán)引用,如果一定要添加該方法,需要顯式調(diào)用 gc模塊的garbage中對象的del方法進(jìn)行處理。