Python垃圾回收機(jī)制總結(jié)
Python 垃圾回收機(jī)制
內(nèi)存管理
Python中的內(nèi)存管理機(jī)制的層次結(jié)構(gòu)提供了4層,其中***層則是C運(yùn)行的malloc和free接口,往上的三層才是由Python實(shí)現(xiàn)并且維護(hù)的,***層則是在第0層的基礎(chǔ)之上對(duì)其提供的接口進(jìn)行了統(tǒng)一的封裝,因?yàn)槊總€(gè)系統(tǒng)都可能差異性。
內(nèi)存池
Python為了避免頻繁的申請(qǐng)和刪除內(nèi)存所造成系統(tǒng)切換于用戶態(tài)和核心態(tài)的性能問(wèn)題,從而引入了內(nèi)存池機(jī)制,專門用來(lái)管理小內(nèi)存的申請(qǐng)和釋放。內(nèi)存池分為四層:block、pool、arena和內(nèi)存池。如下圖:
block:有很多種block,不同種類的block都有不同的內(nèi)存大小,申請(qǐng)內(nèi)存的時(shí)候只需要找到適合自身大小的block即可,當(dāng)然申請(qǐng)的內(nèi)存也是存在一個(gè)上限,如果超過(guò)這個(gè)上限,則退化到使用***層的malloc進(jìn)行申請(qǐng)。
pool:一個(gè)pool管理著一堆有固定大小的內(nèi)存塊,其大小通常為一個(gè)系統(tǒng)內(nèi)存頁(yè)的大小。
arena:多個(gè)pool組合成一個(gè)arena。
內(nèi)存池:一個(gè)整體的概念。
垃圾回收
Python的GC模塊主要運(yùn)用了引用計(jì)數(shù)來(lái)跟蹤和回收垃圾。在引用計(jì)數(shù)的基礎(chǔ)上,還可以通過(guò)“標(biāo)記-清除”解決容器對(duì)象可能產(chǎn)生的循環(huán)引用的問(wèn)題。通過(guò)分代回收以空間換取時(shí)間進(jìn)一步提高垃圾回收的效率。
引用計(jì)數(shù)
原理:當(dāng)一個(gè)對(duì)象的引用被創(chuàng)建或者復(fù)制時(shí),對(duì)象的引用計(jì)數(shù)加1;當(dāng)一個(gè)對(duì)象的引用被銷毀時(shí),對(duì)象的引用計(jì)數(shù)減1,當(dāng)對(duì)象的引用計(jì)數(shù)減少為0時(shí),就意味著對(duì)象已經(jīng)再?zèng)]有被使用了,可以將其內(nèi)存釋放掉。
優(yōu)點(diǎn):引用計(jì)數(shù)有一個(gè)很大的優(yōu)點(diǎn),即實(shí)時(shí)性,任何內(nèi)存,一旦沒(méi)有指向它的引用,就會(huì)被立即回收,而其他的垃圾收集技術(shù)必須在某種特殊條件下才能進(jìn)行無(wú)效內(nèi)存的回收。
缺點(diǎn):但是它也有弱點(diǎn),引用計(jì)數(shù)機(jī)制所帶來(lái)的維護(hù)引用計(jì)數(shù)的額外操作與Python運(yùn)行中所進(jìn)行的內(nèi)存分配和釋放,引用賦值的次數(shù)是成正比的,這顯然比其它那些垃圾收集技術(shù)所帶來(lái)的額外操作只是與待回收的內(nèi)存數(shù)量有關(guān)的效率要高。同時(shí),引用技術(shù)還存在另外一個(gè)很大的問(wèn)題-循環(huán)引用,因?yàn)閷?duì)象之間相互引用,每個(gè)對(duì)象的引用都不會(huì)為0,所以這些對(duì)象所占用的內(nèi)存始終都不會(huì)被釋放掉。如下:
標(biāo)記-清除
標(biāo)記-清除的出現(xiàn)打破了循環(huán)引用,也就是它只關(guān)注那些可能會(huì)產(chǎn)生循環(huán)引用的對(duì)象,顯然,像是PyIntObject、PyStringObject這些不可變對(duì)象是不可能產(chǎn)生循環(huán)引用的,因?yàn)樗鼈儍?nèi)部不可能持有其它對(duì)象的引用。Python中的循環(huán)引用總是發(fā)生在container對(duì)象之間,也就是能夠在內(nèi)部持有其它對(duì)象的對(duì)象,比如list、dict、class等等。這也使得該方法帶來(lái)的開(kāi)銷只依賴于container對(duì)象的的數(shù)量。
原理:將集合中對(duì)象的引用計(jì)數(shù)復(fù)制一份副本,這個(gè)計(jì)數(shù)副本的作用是尋找root object集合(該集合中的對(duì)象是不能被回收的)。當(dāng)成功尋找到root object集合之后,首先將現(xiàn)在的內(nèi)存鏈表一分為二,一條鏈表中維護(hù)root object集合,成為root鏈表,而另外一條鏈表中維護(hù)剩下的對(duì)象,成為unreachable鏈表。一旦在標(biāo)記的過(guò)程中,發(fā)現(xiàn)現(xiàn)在的unreachable可能存在被root鏈表中直接或間接引用的對(duì)象,就將其從unreachable鏈表中移到root鏈表中;當(dāng)完成標(biāo)記后,unreachable鏈表中剩下的所有對(duì)象就是名副其實(shí)的垃圾對(duì)象了,接下來(lái)的垃圾回收只需限制在unreachable鏈表中即可。
缺點(diǎn):該機(jī)制所帶來(lái)的額外操作和需要回收的內(nèi)存塊成正比。
分代
原理:將系統(tǒng)中的所有內(nèi)存塊根據(jù)其存活時(shí)間劃分為不同的集合,每一個(gè)集合就成為一個(gè)“代”,垃圾收集的頻率隨著“代”的存活時(shí)間的增大而減小。也就是說(shuō),活得越長(zhǎng)的對(duì)象,就越不可能是垃圾,就應(yīng)該減少對(duì)它的垃圾收集頻率。那么如何來(lái)衡量這個(gè)存活時(shí)間:通常是利用幾次垃圾收集動(dòng)作來(lái)衡量,如果一個(gè)對(duì)象經(jīng)過(guò)的垃圾收集次數(shù)越多,可以得出:該對(duì)象存活時(shí)間就越長(zhǎng)。