python進階:垃圾回收

垃圾回收

垃圾回收一:

1.小整數對象池

整數在程序中的使用很是普遍,Python爲了優化速度,使用了小整數對象池, 避免爲整數頻繁申請和銷燬內存空間。java

Python 對小整數的定義是 [-5, 257) 這些整數對象是提早創建好的,不會被垃圾回收。在一個 Python 的程序中,全部位於這個範圍內的整數使用的都是同一個對象.python

同理,單個字母也是這樣的。app

可是當定義2個相同的字符串時,引用計數爲0,觸發垃圾回收函數

2,大整數對象池

每個大整數,均建立一個新的對象。優化

 

3.intern機制

python靠引用計數去維護什麼時候釋放內存spa

4.總結

  • 小整數[-5,257)共用對象,常駐內存
  • 單個字符共用對象,常駐內存
  • 單個單詞,不可修改,默認開啓intern機制,共用對象,引用計數爲0,則銷燬 
  • 字符串(含有空格),不可修改,沒開啓intern機制,不共用對象,引用計數爲0,銷燬 
  • 大整數不共用內存,引用計數爲0,銷燬 
  • 數值類型和字符串類型在 Python 中都是不可變的,這意味着你沒法修改這個對象的值,每次對變量的修改,其實是建立一個新的對象 

垃圾回收二:

 python裏也同java同樣採用了垃圾收集機制,不過不同的是: python採用的是引用計數機制爲主,標記-清除和分代收集兩種機制爲輔的策略操作系統

引用計數機制:debug

python裏每個東西都是對象,它們的核心就是一個結構體:PyObject日誌

typedef struct_object {
    int ob_refcnt;
    struct_typeobject *ob_type;
} PyObject;

PyObject是每一個對象必有的內容,其中ob_refcnt就是作爲引用計數。當一個對象有新的引用時,它的ob_refcnt就會增長,當引用它的對象被刪除,它的ob_refcnt就會減小;當引用計數爲0時,該對象生命就結束了。 code

引用計數機制的優勢:
  • 簡單
  • 實時性:一旦沒有引用,內存就直接釋放了。不用像其餘機制等到特定時機。實時性還帶來一個好處:處理回收內存的時間分攤到了平時。
引用計數機制的缺點:
  • 維護引用計數消耗資源
  • 循環引用
list1 = [] list2 = [] list1.append(list2) list2.append(list1)

ist1與list2相互引用,若是不存在其餘對象對它們的引用,list1與list2的引用計數也仍然爲1,所佔用的內存永遠沒法被回收,這將是致命的。 對於現在的強大硬件,缺點1尚可接受,可是循環引用致使內存泄露,註定python還將引入新的回收機制。(標記清除和分代收集)

GC系統所承擔的工做遠比"垃圾回收"多得多。實際上,它們負責三個重要任務。它們

  • 爲新生成的對象分配內存
  • 識別那些垃圾對象,而且
  • 從垃圾對象那回收內存。

當建立對象時,python當即向操做系統請求內存

標記-清除:

中止程序,加標記,把未被標記的對象看成垃圾處理

垃圾回收三:gc模塊

1.致使引用計數+1的狀況

  • 對象被建立,例如a=23
  • 對象被引用,例如b=a
  • 對象被做爲參數,傳入到一個函數中,例如func(a)
  • 對象做爲一個元素,存儲在容器中,例如list1=[a,a]

2.致使引用計數-1的狀況

  • 對象的別名被顯式銷燬,例如del a
  • 對象的別名被賦予新的對象,例如a=24
  • 一個對象離開它的做用域,例如f函數執行完畢時,func函數中的局部變量(全局變量不會)
  • 對象所在的容器被銷燬,或從容器中刪除對象

3.查看一個對象的引用計數

import sys y='hh'
print(sys.getrefcount(y))

4.循環引用致使內存泄露

import gc class ClassA(): def __init__(self): print('object born,id:%s'%str(hex(id(self)))) def f2(): while True: c1 = ClassA() c2 = ClassA() c1.t = c2 c2.t = c1 del c1 del c2 #把python的gc關閉
gc.disable() f2()

執行f2(),進程佔用的內存會不斷增大。

  • 建立了c1,c2後這兩塊內存的引用計數都是1,執行c1.t=c2c2.t=c1後,這兩塊內存的引用計數變成2.
  • 在del c1後,內存1的對象的引用計數變爲1,因爲不是爲0,因此內存1的對象不會被銷燬,因此內存2的對象的引用數依然是2,在del c2後,同理,內存1的對象,內存2的對象的引用數都是1。
  • 雖然它們兩個的對象都是能夠被銷燬的,可是因爲循環引用,致使垃圾回收器都不會回收它們,因此就會致使內存泄露。

5.什麼狀況下觸發python垃圾回收

1).import gc 

 gc.get_threshold()

輸出:(700,10,10)      (當沒有釋放的對象個數超過700,即開始0級垃圾回收,0級垃圾回收超過10次即開始1級垃圾回收,1級垃圾回收清除包括0級垃圾,1級垃圾回收超過10次,即開始2級垃圾回收,2級垃圾回收清除包括0級,1級垃圾)

2).垃圾回收機制python默認開啓的,gc.disabled可關閉垃圾回收機制,當程序完成時,垃圾最後仍被回收

3).當gc.disabled時,gc.collect手動開啓垃圾回收機制

6.gc模塊經常使用功能解析

gc模塊提供一個接口給開發者設置垃圾回收的選項。上面說到,採用引用計數的方法管理內存的一個缺陷是循環引用,而gc模塊的一個主要功能就是解決循環引用的問題。

經常使用函數:

一、gc.set_debug(flags) 設置gc的debug日誌,通常設置爲gc.DEBUG_LEAK

二、gc.collect([generation]) 顯式進行垃圾回收,能夠輸入參數,0表明只檢查第一代的對象,1表明檢查一,二代的對象,2表明檢查一,二,三代的對象,若是不傳參數,執行一個full collection,也就是等於傳2。 返回不可達(unreachable objects)對象的數目

三、gc.get_threshold() 獲取的gc模塊中自動執行垃圾回收的頻率。

四、gc.set_threshold(threshold0[, threshold1[, threshold2]) 設置自動執行垃圾回收的頻率。

五、gc.get_count() 獲取當前自動執行垃圾回收的計數器,返回一個長度爲3的列表

相關文章
相關標籤/搜索