關於 Python 記憶體回收機制的初步認識
一、前言
Python 是一門進階語言,使用起來類似於自然語言,開發的時候自然十分方便快捷,原因是Python在背後為我們默默做了很多事情,其中一件就是記憶體回收,來解決記憶體管理,記憶體流失的問題。
記憶體流失:當程式不停運行,有一部分對象沒有作用,但所佔記憶體沒有被釋放,伺服器記憶體隨時間越來越少,最終導致系統的崩潰,所以記憶體流失是一個需要重點關注的問題。
二、引用計數
Python 標記一個對象是否還有用的方法就是用引用計數,以下情形會為該對象的計數+1:
1. 建立時
2. 被引用時
3. 作為參數傳入函數時
相反,以下情形會為該對象的計數-1:
1. 被del
2. 被重引用
3. 函數執行完畢
查看某一元素的計數可以通過 sys.getrefcount(),當引用計數為0 的時候,記憶體就會被釋放。
可以想到和其他記憶體回收相比,Python的機制優點很明顯,就是即時性,Python的gc 模組就是開放的介面用以管理。
也可以很容易猜到這樣的缺點就是效能相對較低,看過這樣的報道,instagram 通過禁用 gc 模組,效能提升10%!
三、 循環參考
有一種特殊情況,當兩個或多個變數互相循環參考的時候,按照計數引用的機制就無法處理了
a = []
b = []
a.append(b)
b.append(a)
print(a,b)
a,b 的引用計數均為2,無法回收兩者記憶體
四、解決方案
1. 通過 ”標記-清除“ 來解決迴圈調用問題:
記憶體回收行程定時去尋找這類迴圈調用,並清除
具體是 先從 根對象集合副本中 開始尋找,這些對象計數不為0,沒有被清除
然後一個個檢測,將其分為可達對象和不可達對象,底層通過鏈表的資料結構實現,通過操作副本清除標記,來在不影響原資料的情況下,判斷是否為迴圈調用
最後將不可達對象清除,釋放記憶體,效率較低。
有三種情況會觸發記憶體回收:
1.調用gc.collect(),
2.當gc模組的計數器達到閥值的時候。
3.程式退出的時候
2.分代回收,利用 “空間換時間”策略提高效率:
有些記憶體塊存留時間從開始到結束,有些則很短,所以同樣對他們進行記憶體回收是很浪費的一件事情,
所有對象開始被劃分到零代中,Python 預設 有三代,一個代就是一個鏈表
年輕代中的對象優先處理,經曆垃圾處理次數愈多的,越“老資格” ,就會上升,最終放在第二代中。
備忘:
Python的記憶體回收機制是通過檢測數量是否到達閾值來決定是否進行。
Python 這方面源碼是c寫的,暫時看不懂,留待以後搞懂鏈表結構再來研究,
gc 模組 留待以後研究。
本文永久更新連結地址:https://www.bkjia.com/Linux/2018-03/151119.htm