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

WBOY
發布: 2022-10-12 15:32:35
轉載
1639 人瀏覽過

本篇文章為大家帶來了關於Python的相關知識,其中主要介紹了關於CPython的相關問題,CPython的垃圾收集器是Python內建的為了解決循環引用問題的方法,下面一起來看一下,希望對大家有幫助。

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

【相關推薦: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)
[{&#39;name&#39;: &#39;bob&#39;, &#39;friend&#39;: <__main__.MyNamedClass object at 0x7ff29a095d60>}, <class &#39;__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中的垃圾收集器的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:juejin.im
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板