Python垃圾回收包括引用計(jì)數(shù)、標(biāo)記清除和分代回收
引用計(jì)數(shù)
引用計(jì)數(shù)是一種垃圾收集機(jī)制,當(dāng)一個(gè)python對(duì)象被引用時(shí),引用計(jì)數(shù)加1,當(dāng)一個(gè)對(duì)象的引用為0時(shí),該對(duì)象會(huì)被當(dāng)做垃圾回收。
fromsysimportgetrefcount
l1=[1,2,3]
print(getrefcount(l1))#查看引用計(jì)數(shù)
l2=l1
print(getrefcount(l2))
執(zhí)行結(jié)果:
2
3
在使用getrefcount()的時(shí)候,變量作為參數(shù)傳進(jìn)去,會(huì)多一次引用。
del語句會(huì)刪除對(duì)象的一個(gè)引用。請(qǐng)看下面的例子:
fromsysimportgetrefcount
classTestObjectA():
def__init__(self):
print("hello!!!")
def__del__(self):
print("bye!!!")
a=TestObjectA()
b=a
c=a
print(getrefcount(c))
dela
print(getrefcount(c))
delb
print(getrefcount(c))
delc
print("666")
執(zhí)行結(jié)果:
hello!!!
4
3
2
bye!!!
666
方法__del__的作用是當(dāng)對(duì)象被銷毀時(shí)調(diào)用。其中dela刪除了變量a,但是對(duì)象TestObjectA仍然存在,它還被b和c引用,所以不會(huì)被回收,引用計(jì)數(shù)為0時(shí)會(huì)被回收。上面的例子中,將a,b,c都刪除后引用的對(duì)象被回收(打印“666”之前)。
另外重新賦值也會(huì)刪除對(duì)象的一個(gè)引用。
標(biāo)記清除
如果出現(xiàn)了循環(huán)引用,引用計(jì)數(shù)方法就無法回收,導(dǎo)致內(nèi)存泄漏。先來看下面的例子:
classTestObjectA(dict):
def__init__(self):
print("A:hello!!!")
def__del__(self):
print("A:bye!!!")
classTestObjectB(dict):
def__init__(self):
print("B:hello!!!")
def__del__(self):
print("B:bye!!!")
a=TestObjectA()
b=TestObjectB()
a['1']=b
b['1']=a
dela
delb
print("666")
執(zhí)行結(jié)果:
A:hello!!!
B:hello!!!
666
A:bye!!!
B:bye!!!
上面的代碼存在循環(huán)引用,刪除a和b之后,它們的引用計(jì)數(shù)還是1,仍然大于0,不會(huì)被回收(打印“666”之后)。
標(biāo)記清除可解決循環(huán)引用問題,從根對(duì)象(寄存器和程序棧上的引用)出發(fā),遍歷對(duì)象,將遍歷到的對(duì)象打上標(biāo)記(垃圾檢測(cè)),然后在內(nèi)存中清除沒有標(biāo)記的對(duì)象(垃圾回收)。上面的例子中,a和b相互引用,如果與其他對(duì)象沒有引用關(guān)系就不會(huì)遍歷到它,也就不會(huì)被標(biāo)記,所以會(huì)被清除。
分代回收
如果頻繁進(jìn)行標(biāo)記清除會(huì)影響Python性能,有很多對(duì)象,清理了很多次他依然存在,可以認(rèn)為,這樣的對(duì)象不需要經(jīng)常回收,也就是說,對(duì)象存在時(shí)間越長(zhǎng),越可能不是垃圾。
將回收對(duì)象進(jìn)行分代(一共三代),每代回收的時(shí)間間隔不同,其中新創(chuàng)建的對(duì)象為0代,如果一個(gè)對(duì)象能在第0代的垃圾回收過程中存活下來,那么它就被放入到1代中,如果1代里的對(duì)象在第1代的垃圾回收過程中存活下來,則會(huì)進(jìn)入到2代。
gc模塊
以下三種情況會(huì)啟動(dòng)垃圾回收:
·調(diào)用gc.collect():強(qiáng)制對(duì)所有代執(zhí)行一次回收
·當(dāng)gc模塊的計(jì)數(shù)器達(dá)到閥值的時(shí)候。
·程序退出的時(shí)候
gc模塊函數(shù):
·gc.enable():?jiǎn)⒂米詣?dòng)垃圾回收
·gc.disable():停用自動(dòng)垃圾回收
·gc.isenabled():如果啟用了自動(dòng)回收則返回True。
·gc.collect(generation=2):不設(shè)置參數(shù)會(huì)對(duì)所有代執(zhí)行一次回收
·gc.set_threshold(threshold0[,threshold1[,threshold2]]):設(shè)置垃圾回收閾值
·gc.get_count():當(dāng)前回收計(jì)數(shù)
·垃圾回收啟動(dòng)的默認(rèn)閾值
importgc
print(gc.get_threshold())
輸出:
(700,10,10)
700是垃圾回收啟動(dòng)的閾值,對(duì)象分配數(shù)量減去釋放數(shù)量的值大于700時(shí),就會(huì)開始進(jìn)行垃圾回收,每10次0代垃圾回收,會(huì)導(dǎo)致一次1代回收;而每10次1代的回收,才會(huì)有1次的2代回收??梢允褂胹et_threshold()方法重新設(shè)置。
以上內(nèi)容為大家介紹了Python垃圾回收,希望對(duì)大家有所幫助,如果想要了解更多Python相關(guān)知識(shí),請(qǐng)關(guān)注IT培訓(xùn)機(jī)構(gòu):千鋒教育。http://m.2667701.com/