python垃圾回收机制(GC)相关问题
在使用python中很少遇到內(nèi)存溢出的問題,也不關(guān)心內(nèi)存的管理問題,這是高級語言自帶的處理機制,將內(nèi)部的垃圾空間清除。
要清楚是怎么回收垃圾的,那我們應(yīng)該先明白什么情況下產(chǎn)生垃圾,就涉及到python內(nèi)部的對象管理方法。
對于int類型的變量在[5, 257)范圍內(nèi)是共用對象常駐內(nèi)存,不在此范圍內(nèi)的話一個變量建立一個對象。
單個字符是常駐內(nèi)存共用對象,字符串是引用計數(shù)機制(相同的值指向同一個對象)
a?=?256a1?=?256
b?=?257
b1?=?257
id(a)?==?id(a1)
Out[6]:?True
id(b)?==?id(b1)
Out[7]:?False
c1?=?'a'
c?=?'a'
d?=?'sdsds4'
d1?=?'sdsds4'
id(c)?==?id(c1)
Out[12]:?True
id(d)?==?id(d1)
Out[13]:?True
首先在對象管理上已經(jīng)做到了最小化的內(nèi)存開銷,并不是一個變量一個對象,而是多種方案結(jié)合。
那再看垃圾回收的機制,與C/C++有別的是python內(nèi)部實現(xiàn)了自動的垃圾回收,而無需用戶考慮什么時候銷毀一個對象或變量。python的垃圾回收機制是以引用計數(shù)機制為主,標(biāo)記-清除和分代收集兩種機制為輔的綜合方案。
引用計數(shù)機制
上面說的字符串內(nèi)存管理就是引用計數(shù),當(dāng)創(chuàng)建一個字符串a(chǎn)='test',之后再創(chuàng)建一個b = 'test‘,其實變量a/b指向的是一個對象’test',這個對象被引用的次數(shù)是2,但是當(dāng)我們改變b='test1‘,這個時候b新建了一個對象'test1'并且引用計數(shù)為1,相應(yīng)的a引用計數(shù)也變?yōu)榱?,這就是引用計數(shù)。
那么怎么通過引用計數(shù)回收垃圾對象呢?還是上面那個案例,此時再把變量a賦值a='test2',那么又新建了一個對象'test2'并且引用計數(shù)為1,此時之前的'test'引用計數(shù)變?yōu)?,就意味沒有任何變量使用了該對象,那這個對象就是垃圾對象被銷毀。
引用計數(shù)簡單方便但是也有弊端:計數(shù)占用內(nèi)存、在相互引用的對象中計數(shù)永遠不會變?yōu)?,所以還引入了標(biāo)記-清除和分代收集。
標(biāo)記-清除
標(biāo)記清除的概念類似于引用計數(shù),只是不同的是當(dāng)引用計數(shù)為0的時候就給這個對象打上一個標(biāo)簽”可清除“,但是不會立馬清除,而是會等到系統(tǒng)給程序分配的內(nèi)存要用完之時,停下來將可清除標(biāo)簽的對象銷毀然后繼續(xù)。
分代回收
首先看上面說的引用計數(shù)的弊端在兩個變量循環(huán)引用中,計數(shù)永遠不可能是0.
b?=?[3,4]a?=?[1,2]
a.append(b)
b.append(a)
a
Out[25]:?[1,?2,?[3,?4,?[...]]]
b
Out[26]:?[3,?4,?[1,?2,?[...]]]
del?a
b
Out[29]:?[3,?4,?[1,?2,?[...]]]
當(dāng)刪除a/b變量時對應(yīng)的內(nèi)存對象應(yīng)用計數(shù)還是1是無法刪除的,此時分代回收就發(fā)揮了他的作用,當(dāng)創(chuàng)建一個對象是將它向上面對象一個放在一個抽象的鏈條上,這條鏈條就是零代鏈條。
然后當(dāng)零代鏈條上對象數(shù)達到閥值就對上面相互引用的對象進行檢測,將相互引用的對象的計數(shù)減1,再標(biāo)記清除垃圾,此時剩下的對象移到一代鏈條,當(dāng)一代鏈條到達閥值就重復(fù)零代的檢測方式,將剩下對象移到二代,就以此類推進行下去。
總結(jié)
以上是生活随笔為你收集整理的python垃圾回收机制(GC)相关问题的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2、Flutter Widget(IOS
- 下一篇: 利用jvisualvm分析JVM,进行性