1. 程式人生 > 程式設計 >Python垃圾回收機制三種實現方法

Python垃圾回收機制三種實現方法

引用計數

Python語言預設採用的垃圾收集機制是『引用計數法 Reference Counting』,該演算法最早George E. Collins在1960的時候首次提出,50年後的今天,該演算法依然被很多程式語言使用。

『引用計數法』的原理是:每個物件維護一個ob_ref欄位,用來記錄該物件當前被引用的次數,每當新的引用指向該物件時,它的引用計數ob_ref加1,每當該物件的引用失效時計數ob_ref減1,一旦物件的引用計數為0,該物件立即被回收,物件佔用的記憶體空間將被釋放

缺點:它的缺點是需要額外的空間維護引用計數,這個問題是其次的,不過最主要的問題是它不能解決物件的“迴圈引用”,因此,也有很多語言比如Java並沒有採用該演算法做來垃圾的收集機制。

import sys
class A():
  def __init__(self):
    '''初始化物件'''
    print('object born id:%s' %str(hex(id(self))))
  def f1():
  '''迴圈引用'''
  while True:
    c1=A()
    c2=A()
    c1.t=c2
    c2.t=c1
    del c1
    del c2

例項化c1,c2後,這兩個物件的引用計數都是1,執行c1.t=c2和c2.t=c1後,引用計數變成2.
在del c1後,記憶體c1的物件的引用計數變為1,由於不是為0,所以c1的物件不會被銷燬,同理,在del c2後也是一樣的。

雖然它們兩個的物件都是可以被銷燬的,但是由於迴圈引用,導致垃圾回收器都不會回收它們,所以就會導致記憶體洩露。

標記清楚

標記清除(Mark—Sweep)』演算法是一種基於追蹤回收(tracing GC)技術實現的垃圾回收演算法。它分為兩個階段:第一階段是標記階段,GC會把所有的『活動物件』打上標記,第二階段是把那些沒有標記的物件『非活動物件』進行回收。那麼GC又是如何判斷哪些是活動物件哪些是非活動物件的呢?

Python垃圾回收機制三種實現方法

物件之間通過引用(指標)連在一起,構成一個有向圖,物件構成這個有向圖的節點,而引用關係構成這個有向圖的邊。從根物件(root object)出發,沿著有向邊遍歷物件,可達的(reachable)物件標記為活動物件,不可達的物件就是要被清除的非活動物件。根物件就是全域性變數、呼叫棧、暫存器。 mark-sweepg 在上圖中,我們把小黑圈視為全域性變數,也就是把它作為root object,從小黑圈出發,物件1可直達,那麼它將被標記,物件2、3可間接到達也會被標記,而4和5不可達,那麼1、2、3就是活動物件,4和5是非活動物件會被GC回收。

標記清除演算法作為 Python 的輔助垃圾收集技術主要處理的是一些容器物件,比如 list、dict、tuple,instance 等,因為對於字串、數值物件是不可能造成迴圈引用問題。Python使用一個雙向連結串列將這些容器物件組織起來。不過,這種簡單粗暴的標記清除演算法也有明顯的缺點

缺點:清除非活動的物件前它必須順序掃描整個堆記憶體,哪怕只剩下小部分活動物件也要掃描所有物件

分代回收

分代回收是一種以空間換時間的操作方式,Python 將記憶體根據物件的存活時間劃分為不同的集合,每個集合稱為一個代,Python將記憶體分為了3“代”,分別為年輕代(第0代)、中年代(第1代)、老年代(第2代),他們對應的是3個連結串列,它們的垃圾收集頻率與物件的存活時間的增大而減小。

新建立的物件都會分配在年輕代,年輕代連結串列的總數達到上限時,Python垃圾收集機制就會被觸發,把那些可以被回收的物件回收掉,而那些不會回收的物件就會被移到中年代去,依此類推,老年代中的物件是存活時間最久的物件,甚至是存活於整個系統的生命週期內。

同時,分代回收是建立在標記清除技術基礎之上。分代回收同樣作為Python的輔助垃圾收集技術處理那些容器物件

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。