一文了解CPython中的垃圾收集器

2022-10-12 18:01:02
本篇文章給大家帶來了關於Python的相關知識,其中主要介紹了關於CPython的相關問題,CPython的垃圾收集器是Python內建的為了解決迴圈參照問題的方法,下面一起來看一下,希望對大家有幫助。

程式設計師必備介面測試偵錯工具:

【相關推薦:Python3視訊教學

CPython 中的垃圾收集器

CPython 的垃圾收集器(簡稱GC)是 Python 內建的為了解決迴圈參照問題的方法。預設情況下,它總是在後臺執行,並且每隔一段時間就會發揮它的魔力,所以你不必擔心迴圈參照物會堵塞你的記憶體。

垃圾收集器被設計為從 CPython 的工作記憶體中找到並刪除迴圈參照物件。它通過以下方式完成這一工作。

  • 檢測迴圈參照的物件

  • 呼叫最終的 __del__ 方法

  • 它從每個物件中刪除指標(以此來解決迴圈問題),只有當迴圈在步驟 2 之後仍然是孤立的

在這個過程完成後,以前在迴圈中的每個物件現在的參照計數都是 0 ,因此此物件將從記憶體中刪除。

雖然它是自動工作的,但實際上我們可以把它作為一個模組從標準庫中匯入。舉例如下:

import gc
登入後複製

檢測迴圈參照

CPython 的垃圾收集器會跟蹤記憶體中存在的各種物件--但不是所有的物件。我們可以範例化一些物件,看看垃圾收集器是否會收集它們。

>>> gc.is_tracked("a string")
False
>>> gc.is_tracked(["a", "list"])
True
登入後複製

如果一個物件可以包含指標,這就使它有能力形成迴圈參照結構的一部分--而這正是垃圾檢測器存在的目的,即檢測和拆除。在 Python 中這樣的物件通常被稱為 "容器物件"。

所以,垃圾收集器需要知道任何有可能作為迴圈參照的一部分而存在的物件。字串不能,所以 "一個字串 "不會被垃圾收集器追蹤。列表(正如我們已經看到的)能夠包含指標,因此 ['a', 'list'] 被跟蹤。

使用者定義的類的任何範例也將被垃圾收集器跟蹤,因為我們總是可以在它們身上設定任意的屬性(指標)。

>>> Wade = MyNameClass("Wade")
>>> gc.is_tracked(Wade)
True
登入後複製

所以,垃圾收集器知道所有有可能形成迴圈參照的物件。它怎麼知道是否已經形成迴圈參照呢?

它也知道每個物件中的所有指標,以及它們所指向的位置。我們可以看到這個動作。

>>> my_list = ["a", "list"]
>>> gc.get_referents(my_list)
['list', 'a']
登入後複製

get_referents 方法(也稱為遍歷方法)接收一個物件,並返回它所包含的物件指標的列表(它的參照)。因此,上面的列表包含指向其每個元素的指標,這些元素都是字串。

讓我們在一個物件的迴圈中看看 get_referents 方法(雖然還不是一個迴圈參照,因為這些物件仍然可以從名稱空間中被存取)。

>>> jane = MyNamedClass("Jane")
>>> bob = MyNamedClass("Bob")
>>> jane.friend = bob
>>> bob.friend = jane
>>> gc.get_referents(bob)
[{'name': 'bob', 'friend': <__main__.MyNamedClass object at 0x7ff29a095d60>}, <class '__main__
登入後複製

在這個迴圈中,我們可以看到由 bob 指向的物件包含指向以下內容的指標:它的屬性字典,包含 bob 的名字 (bob) 和它的朋友 (同樣由 jane 指向的 MyNamedClass 範例) 。bob 物件也有一個指向類物件本身的指標,因為 bob.class 將返回那個類物件。

當垃圾收集器執行時,它檢查它所知道的每個物件(也就是當你呼叫 gc.is_tracked 時返回True的任何物件)是否可以從名稱空間到達。它通過跟蹤來自名稱空間的所有指標,以及這些指標所指向的物件中的指標,以此類推,直到它建立起所有可從程式碼中存取的東西的整個檢視。

如果在做完這些之後,GC 發現存在一些不能從名稱空間到達的物件,那麼它可以把這些物件清除掉。

記住,任何仍在記憶體中的物件必須有一個非零的參照計數,否則它們會因為參照計數而被刪除。對於那些無法到達但仍有非零參照計數的物件,它們必須是迴圈參照的一部分,這就是為什麼我們如此關心這些發生的可能性。

讓我們回到參照迴圈,jane 和 bob,通過從名稱空間中移除指標,把這個迴圈變成一個迴圈的隔離。

>>> del jane
>>> del bob
登入後複製

現在,我們已經瞭解了垃圾收集器所要解決的確切情況。我們可以通過呼叫 gc.collect() 來觸發手動垃圾收集。

>>> gc.collect()
Deleting Bob!
Deleting Jane!
4
登入後複製

預設情況下,垃圾收集器會每隔一段時間自動執行這個動作(因為越來越多的物件在CPython執行時被建立和銷燬)。

在上面的程式碼片段中,我們看到的輸出包含了來自 MyNamClass 的 __del__ 方法的列印語句,在最後有一個數位--在這個例子中,是 4。 這個數位是由垃圾收集器本身輸出的,它告訴我們有多少物件被移除。

【相關推薦:Python3視訊教學

以上就是一文了解CPython中的垃圾收集器的詳細內容,更多請關注TW511.COM其它相關文章!