Garbage collection(GC)
現在的進階語言如java,c#等,都采用了垃圾收集機制,而不再是c,c++裡使用者自己管理維護記憶體的方式。自己管理記憶體極其自由,可以任意申請記憶體,但如同一把雙刃劍,為大量記憶體洩露,懸空指針等bug埋下隐患。
對于一個字元串、清單、類甚至數值都是對象,且定位簡單易用的語言,自然不會讓使用者去處理如何配置設定回收記憶體的問題。
python裡也同java一樣采用了垃圾收集機制,不過不一樣的是:
python采用的是
引用計數
機制為主,
标記-清除
和
分代收集
兩種機制為輔的政策
GC系統所承擔的工作遠比“垃圾回收”多得多。它們負責三個重要任務:
- 為新生成的對象配置設定記憶體
- 識别那些垃圾對象
- 從垃圾對象回收記憶體
如果将應用程式比作人的身體:所有你所寫的那些優雅的代碼,業務邏輯,算法,應該就是大腦。垃圾回收就是應用程式那顆躍動的心。像心髒為身體其他器官提供血液和營養物那樣,垃圾回收器為你的應該程式提供記憶體和對象。如果垃圾回收器停止工作或運作遲緩,像動脈阻塞,你的應用程式效率也會下降,直至最終死掉。
gc子產品的自動垃圾回收機制
必須要import gc子產品,并且is_enable()=True才會啟動自動垃圾回收。
這個機制的主要作用就是發現并處理不可達的垃圾對象。
垃圾回收=垃圾檢查+垃圾回收
1、引用計數機制:
python裡每一個東西都是對象,它們的核心就是一個結構體:
PyObject
typedef struct_object {
int ob_refcnt; #引用計數
struct_typeobject *ob_type;
} PyObject;
PyObject是每個對象必有的内容,其中ob_refcnt
就是做為引用計數。當一個對象有新的引用時,它的ob_refcnt
就會增加,當引用它的對象被删除,它的ob_refcnt
就會減少
#define Py_INCREF(op) ((op)->ob_refcnt++) //增加計數
#define Py_DECREF(op) \ //減少計數
if (--(op)->ob_refcnt != 0) \
; \
else \
__Py_Dealloc((PyObject *)(op))
import sys
class A(object):
def __init__(self):
"""初始化對象"""
print ('object born id:%s'%str(hex(id(self))))
def f1():
"""循環引用變量與删除變量"""
while True:
c1=A()
del c1
def func(c):
"""getrefcount() 傳回對象的引用計數"""
print ('object refcount is:',sys.getrefcount(c))
if __name__=='__main__':
# 生成對象
a=A()
func(a)
# 增強引用
b=a
func(a)
# 銷毀引用
del b
func(a)
結果:
object born id:0x1043059b0
object refcount is: 4
object refcount is: 5
object refcount is: 4
gc方式1:引用計數
若此對象無其他對象引用,則立馬回收掉
優點:簡單、實時(将處理垃圾時間分攤到運作代碼時,而不是等到一次回收)
缺點:
1.儲存對象引用數會占用一點點記憶體空間
2.每次執行語句都可能更新引用數,不再使用大的資料結構時,會引起大量對象被回收
3.不能處理循環引用的情況
gc方式2:标記-清除(Mark—Sweep)
此方式主要用來處理循環引用的情況,隻有容器對象(list、dict、tuple,instance)才會出現循環引用的情況
處理過程
1.将所有容器對象放到一個雙向連結清單中(連結清單為了友善插入删除),這些對象為0代
2.循環周遊連結清單,如果被本連結清單内的對象引入,自身的被引用數-1,如果被引用數為0,則觸發引用計數回收條件,被回收掉
3.未被回收的對象,更新為1代
『标記清除(Mark—Sweep)』算法是一種基于追蹤回收(tracing GC)技術實作的垃圾回收算法。它分為兩個階段:第一階段是标記階段,GC會把所有的『活動對象』打上标記,第二階段是把那些沒有标記的對象『非活動對象』進行回收。那麼GC又是如何判斷哪些是活動對象哪些是非活動對象的呢?
對象之間通過引用(指針)連在一起,構成一個有向圖,對象構成這個有向圖的節點,而引用關系構成這個有向圖的邊。從根對象(root object)出發,沿着有向邊周遊對象,可達的(reachable)對象标記為活動對象,不可達的對象就是要被清除的非活動對象。根對象就是全局變量、調用棧、寄存器。
何時觸發
1.被引用為0時,立即回收目前對象
2.達到了垃圾回收的門檻值,觸發标記-清除
3.手動調用gc.collect()
4.Python虛拟機退出的時候
連結
python源碼解讀垃圾回收機制
python垃圾回收機制