網(wǎng)站首頁 編程語言 正文
CPython 中的垃圾收集器
CPython 的垃圾收集器(簡稱GC)是 Python 內(nèi)置的為了解決循環(huán)引用問題的方法。默認情況下,它總是在后臺運行,并且每隔一段時間就會發(fā)揮它的魔力,所以你不必擔(dān)心循環(huán)引用物會堵塞你的內(nèi)存。
垃圾收集器被設(shè)計為從 CPython 的工作內(nèi)存中找到并刪除循環(huán)引用對象。它通過以下方式完成這一工作。
- 檢測循環(huán)引用的對象
- 調(diào)用最終的
__del__
方法 - 它從每個對象中刪除指針(以此來解決循環(huán)問題),只有當(dāng)循環(huán)在步驟 2 之后仍然是孤立的
在這個過程完成后,以前在循環(huán)中的每個對象現(xiàn)在的引用計數(shù)都是 0 ,因此此對象將從內(nèi)存中刪除。
雖然它是自動工作的,但實際上我們可以把它作為一個模塊從標(biāo)準(zhǔn)庫中導(dǎo)入。舉例如下:
import gc
檢測循環(huán)引用
CPython 的垃圾收集器會跟蹤內(nèi)存中存在的各種對象--但不是所有的對象。我們可以實例化一些對象,看看垃圾收集器是否會收集它們。
>>> gc.is_tracked("a string") False >>> gc.is_tracked(["a", "list"]) True
如果一個對象可以包含指針,這就使它有能力形成循環(huán)引用結(jié)構(gòu)的一部分--而這正是垃圾檢測器存在的目的,即檢測和拆除。在 Python 中這樣的對象通常被稱為 "容器對象"。
所以,垃圾收集器需要知道任何有可能作為循環(huán)引用的一部分而存在的對象。字符串不能,所以 "一個字符串 "不會被垃圾收集器追蹤。列表(正如我們已經(jīng)看到的)能夠包含指針,因此 ['a', 'list']
被跟蹤。
用戶定義的類的任何實例也將被垃圾收集器跟蹤,因為我們總是可以在它們身上設(shè)置任意的屬性(指針)。
>>> Wade = MyNameClass("Wade") >>> gc.is_tracked(Wade) True
所以,垃圾收集器知道所有有可能形成循環(huán)引用的對象。它怎么知道是否已經(jīng)形成循環(huán)引用呢?
它也知道每個對象中的所有指針,以及它們所指向的位置。我們可以看到這個動作。
>>> my_list = ["a", "list"] >>> gc.get_referents(my_list) ['list', 'a']
get_referents
方法(也稱為遍歷方法)接收一個對象,并返回它所包含的對象指針的列表(它的引用)。因此,上面的列表包含指向其每個元素的指針,這些元素都是字符串。
讓我們在一個對象的循環(huán)中看看 get_referents
方法(雖然還不是一個循環(huán)引用,因為這些對象仍然可以從命名空間中被訪問)。
>>> 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__
在這個循環(huán)中,我們可以看到由 bob 指向的對象包含指向以下內(nèi)容的指針:它的屬性字典,包含 bob 的名字 (bob) 和它的朋友 (同樣由 jane 指向的 MyNamedClass 實例) 。bob 對象也有一個指向類對象本身的指針,因為 bob.class
將返回那個類對象。
當(dāng)垃圾收集器運行時,它檢查它所知道的每個對象(也就是當(dāng)你調(diào)用 gc.is_tracked
時返回True的任何對象)是否可以從命名空間到達。它通過跟蹤來自命名空間的所有指針,以及這些指針?biāo)赶虻膶ο笾械闹羔?,以此類推,直到它建立起所有可從代碼中訪問的東西的整個視圖。
如果在做完這些之后,GC 發(fā)現(xiàn)存在一些不能從命名空間到達的對象,那么它可以把這些對象清除掉。
記住,任何仍在內(nèi)存中的對象必須有一個非零的引用計數(shù),否則它們會因為引用計數(shù)而被刪除。對于那些無法到達但仍有非零引用計數(shù)的對象,它們必須是循環(huán)引用的一部分,這就是為什么我們?nèi)绱岁P(guān)心這些發(fā)生的可能性。
讓我們回到引用循環(huán),jane 和 bob,通過從命名空間中移除指針,把這個循環(huán)變成一個循環(huán)的隔離。
>>> del jane >>> del bob
現(xiàn)在,我們已經(jīng)了解了垃圾收集器所要解決的確切情況。我們可以通過調(diào)用 gc.collect()
來觸發(fā)手動垃圾收集。
>>> gc.collect() Deleting Bob! Deleting Jane! 4
默認情況下,垃圾收集器會每隔一段時間自動執(zhí)行這個動作(因為越來越多的對象在CPython運行時被創(chuàng)建和銷毀)。
在上面的代碼片段中,我們看到的輸出包含了來自 MyNamClass 的 __del__
方法的打印語句,在最后有一個數(shù)字--在這個例子中,是 4。 這個數(shù)字是由垃圾收集器本身輸出的,它告訴我們有多少對象被移除。
參考鏈接:
https://anvil.works/articles/pointers-in-my-python-3
原文鏈接:https://juejin.cn/post/7151052035876618254
相關(guān)推薦
- 2022-11-13 Flutter入門學(xué)習(xí)Dart語言變量及基本使用概念_Dart
- 2022-11-20 Python檢測PE所啟用保護方式詳解_python
- 2022-08-14 Redis+Caffeine兩級緩存的實現(xiàn)_Redis
- 2022-04-02 Python字符串與正則表達式詳細介紹_python
- 2023-01-12 Kotlin?Option與Either及Result實現(xiàn)異常處理詳解_Android
- 2022-08-30 ORACLE分區(qū)表轉(zhuǎn)換在線重定義DBMS_REDEFINITION_oracle
- 2023-11-22 Linux fatal: unable to access ‘https://github xxxx
- 2022-05-07 MongoDB連接和創(chuàng)建數(shù)據(jù)庫的方法講解_MongoDB
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支