您好,登錄后才能下訂單哦!
這篇文章主要介紹了Python中垃圾回收機制指的是什么,具有一定借鑒價值,需要的朋友可以參考下。希望大家閱讀完這篇文章后大有收獲。下面讓小編帶著大家一起了解一下。
一、寫在前面:
我們都知道Python一種面向?qū)ο蟮哪_本語言,對象是Python中非常重要的一個概念。在Python中數(shù)字是對象,字符串是對象,任何事物都是對象,而它們的核心就是一個結(jié)構(gòu)體--PyObject。
typedef struct_object{ int ob_refcnt; struct_typeobject *ob_type; }PyObject;
PyObject是每個對象必有的內(nèi)容,其中ob_refcnt就是做為引用計數(shù)。
二、垃圾回收機制
垃圾回收(Garbage Collection)大家應(yīng)該多多少少都聽過,但是什么是垃圾回收呢?我們這里說的垃圾回收肯定不是把垃圾丟進(jìn)垃圾桶?,F(xiàn)在的高級語言Java,C#等,都采用了垃圾回收機制,而不再是C,C++里用戶自己管理維護內(nèi)存的方式,自己管理內(nèi)存是很自由,但是可能出現(xiàn)內(nèi)存泄漏,懸空指針等問題。而垃圾回收機制作為現(xiàn)代編程語言的自動內(nèi)存管理機制,專注于兩件事:1. 找到內(nèi)存中無用的垃圾資源 2. 清除這些垃圾并把內(nèi)存讓出來給其他對象使用。
三、Python中的垃圾回收
在Python中,垃圾回收機制主要是以引用計數(shù)為主要手段,以標(biāo)記清除和分代回收機制作為輔助手段實現(xiàn)的。
1、引用計數(shù)
通過前面的介紹,我們已經(jīng)知道PyObject是每個對象必有的內(nèi)容,而當(dāng)一個對象有新的引用時,它的ob_refcnt就會增加,當(dāng)引用它的對象被刪除,它的ob_refcnt就會減少,當(dāng)引用計數(shù)為0時,該對象生命就結(jié)束了。
我們來看看引用計數(shù)+1的情況有什么:
(1)對象被創(chuàng)建:
這里實際上123這個對象并沒有在內(nèi)存中新建,因為在Python啟動解釋器的時候會創(chuàng)建一個小整數(shù)池,在-5~256之間的整數(shù)對象會被自動加載到內(nèi)存中等待調(diào)用。因此a=123是對123這個整數(shù)對象增加了一次引用。而456是不在整數(shù)池里的,需要創(chuàng)建對象,那么最后的引用次數(shù)是2呢?因為sys.getrefcount(b)也是一次引用。
(2)對象被引用:
每一次賦值操作都會增加數(shù)據(jù)的引用次數(shù),要記住引用的變量a、b、c指向的是數(shù)據(jù)456,而不是變量本身。
(3)對象作為參數(shù)傳遞到函數(shù)中:
這里可以很明顯看到在被傳遞到函數(shù)中后,引用計數(shù)增加了1。
(4)對象作為元素儲存到容器中:
這里我們在創(chuàng)建對象之后,把a分別添加到了一個列表和一個元組中,引用計數(shù)都增加了。
雖然引用計數(shù)必須在每次分配合釋放內(nèi)存的時候加入管理引用計數(shù)的操作,然而與其他垃圾回收技術(shù)相比,引用計數(shù)有一個最大的優(yōu)點,那就是“實時性”,如果這個對象沒有引用,內(nèi)存就直接釋放了,而其他垃圾回收技術(shù)必須在某種特殊條件下才能進(jìn)行無效內(nèi)存的回收。但是引用計數(shù)帶來的維護引用計數(shù)的額外操作和Python中進(jìn)行的內(nèi)存分配和釋放,引用的賦值次數(shù)成正比的。除此之外,引用計數(shù)機制的還有一個最大的軟肋--無法解決循環(huán)引用帶來的問題。循環(huán)引用可以使一種引用對象的引用計數(shù)不為0,然而這些對象實際上并沒有被任何外部對象所引用,它們之間只是相互引用,這意味著這組對象所占用的內(nèi)存空間是應(yīng)該被回收的,但是由于循環(huán)引用導(dǎo)致的引用計數(shù)不為0,所以這組對象所占用的內(nèi)存空間永遠(yuǎn)不會被釋放。如下,list1與list2相互引用,如果不存在其他對象對它們的引用,list1與list2的引用計數(shù)也仍然為1,所占用的內(nèi)存永遠(yuǎn)無法被回收,這將是致命的。
list1 = [] list2 = [] list1.append(list2) list2.append(list1)
2、標(biāo)記清除
標(biāo)記清除(Mark—Sweep)算法是一種基于追蹤回收(tracing GC)技術(shù)實現(xiàn)的垃圾回收算法。它分為兩個階段:第一階段是標(biāo)記階段,GC會把所有的活動對象打上標(biāo)記,第二階段是把那些沒有標(biāo)記的對象非活動對象進(jìn)行回收。
對象之間通過引用(指針)連在一起,構(gòu)成一個有向圖,對象構(gòu)成這個有向圖的節(jié)點,而引用關(guān)系構(gòu)成這個有向圖的邊。從根對象(root object)出發(fā),沿著有向邊遍歷對象,可達(dá)的(reachable)對象標(biāo)記為活動對象,不可達(dá)的對象就是要被清除的非活動對象。根對象就是全局變量、調(diào)用棧、寄存器?!?/p>
在上圖中,可以從程序變量直接訪問塊1,并且可以間接訪問塊2和3。程序無法訪問塊4和5。第一步將標(biāo)記塊1,并記住塊2和3以供稍后處理。第二步將標(biāo)記塊2,第三步將標(biāo)記塊3,但不記得塊2,因為它已被標(biāo)記。掃描階段將忽略塊1,2和3,因為它們已被標(biāo)記,但會回收塊4和5。
標(biāo)記清除算法作為Python的輔助垃圾收集技術(shù),主要處理的是一些容器對象,比如list、dict、tuple等,因為對于字符串、數(shù)值對象是不可能造成循環(huán)引用問題。Python使用一個雙向鏈表將這些容器對象組織起來。不過,這種簡單粗暴的標(biāo)記清除算法也有明顯的缺點:清除非活動的對象前它必須順序掃描整個堆內(nèi)存,哪怕只剩下小部分活動對象也要掃描所有對象。
3、分代回收
分代回收是建立在標(biāo)記清除技術(shù)基礎(chǔ)之上的,是一種以空間換時間的操作方式。
Python將內(nèi)存根據(jù)對象的存活時間劃分為不同的集合,每個集合稱為一個代,Python將內(nèi)存分為了3“代”,分別為年輕代(第0代)、中年代(第1代)、老年代(第2代),他們對應(yīng)的是3個鏈表,它們的垃圾收集頻率與對象的存活時間的增大而減小。新創(chuàng)建的對象都會分配在年輕代,年輕代鏈表的總數(shù)達(dá)到上限時,Python垃圾收集機制就會被觸發(fā),把那些可以被回收的對象回收掉,而那些不會回收的對象就會被移到中年代去,依此類推,老年代中的對象是存活時間最久的對象,甚至是存活于整個系統(tǒng)的生命周期內(nèi)。
感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享Python中垃圾回收機制指的是什么內(nèi)容對大家有幫助,同時也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,遇到問題就找億速云,詳細(xì)的解決方法等著你來學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。