Python垃圾回收機制?

  • 引用計數(主要)
  • 標記清除和分代回收(輔助)

 

  • 引用計數

在Python中每一個對象的核心就是一個結構體PyObject,它的內部有一個引用計數 ob_refcnt’

當一個對象被創建出來,他的引用計數就會+1,當對象被引用的時候,計數繼續增加,當引用它的對象被刪除的時候,它的引用計數就會減少。直到變爲0,此時垃圾回收機制就會把它回收。

優點:簡單,實時性

缺點:維護性高,不能解決循環引用。

  • 標記清除

標記清除用來解決循環引用產生的問題,循環引用只有在容器對象纔會產生,比如字典,元祖,列表等。首先爲了追蹤對象,需要每個容器對象維護兩個額外的指針,用來將容器對象組成一個鏈表,指針分別指向前後兩個容器對象,方便插入和刪除。

舉個栗子


 

QA: 爲什麼要搞這兩個鏈表

 

之所以要剖成兩個鏈表,是基於這樣的一種考慮:現在的unreachable可能存在被root鏈表中的對象,直接或間接引用的對象,這些對象是不能被回收的,一旦在標記的過程中,發現這樣的對象,就將其從unreachable鏈表中移到root鏈表中;當完成標記後,unreachable鏈表中剩下的所有對象就是名副其實的垃圾對象了,接下來的垃圾回收只需限制在unreachable鏈表中即可。


分代回收:

 

瞭解分類回收,首先要了解一下,GC的閾值,所謂閾值就是一個臨界點的值。隨着你的程序運行,Python解釋器保持對新創建的對象,以及因爲引用計數爲零而被釋放掉的對象的追蹤。從理論上說,創建==釋放數量應該是這樣子。但是如果存在循環引用的話,肯定是創建>釋放數量,當創建數與釋放數量的差值達到規定的閾值的時候,噹噹噹當~分代回收機制就登場啦。

 

垃圾回收=垃圾檢測+釋放

 

分代回收思想將對象分爲三代(generation 0,1,2),0代表幼年對象,1代表青年對象,2代表老年對象。根據弱代假說(越年輕的對象越容易死掉,老的對象通常會存活更久。) 新生的對象被放入0代,如果該對象在第0代的一次gc垃圾回收中活了下來,那麼它就被放到第1代裏面(它就升級了)。如果第1代裏面的對象在第1代的一次gc垃圾回收中活了下來,它就被放到第2代裏面。

gc.set_threshold(threshold0[,threshold1[,threshold2]])設置gc每一代垃圾回收所觸發的閾值。

 

從上一次第0代gc後,如果分配對象的個數減去釋放對象的個數大於threshold0,那麼就會對第0代中的對象進行gc垃圾回收檢查。

從上一次第1代gc後,如果第0代被gc垃圾回收的次數大於threshold1,那麼就會對第1代中的對象進行gc垃圾回收檢查。

從上一次第2代gc後,如果第1代被gc垃圾回收的次數大於threshold2,那麼就會對第2代中的對象進行gc垃圾回收檢查。