1. 程式人生 > >python深入之python記憶體管理機制(重點)

python深入之python記憶體管理機制(重點)

關於python的儲存問題

(1)由於python中萬物皆物件,所以python的儲存問題是物件的儲存問題,並且對於每個物件,python會分配一塊記憶體空間去儲存它

(2)對於整數和短小的字元等,python會執行快取機制,即將這些物件進行快取,不會為相同的物件分配多個記憶體空間

(3)容器物件,如列表、元組、字典等,儲存的其他物件,僅僅是其他物件的引用,即地址,並不是這些物件本身

關於引用計數器

(1)一個物件會記錄著引用自己的物件的個數,每增加一個引用,個數加一,每減少一個引用,個數減一

(2)檢視引用物件個數的方法:匯入sys模組,使用模組中的getrefcount(物件)方法,由於這裡也是一個引用,故輸出的結果多1

(3)增加引用個數的情況:1.物件被建立p = Person(),增加1;2.物件被引用p1 = p,增加1;3.物件被當作引數傳入函式func(object),增加2,原因是函式中有兩個屬性在引用該物件;4.物件儲存到容器物件中l = [p],增加1

(4)減少引用個數的情況:1.物件的別名被銷燬del p,減少1;2.物件的別名被賦予其他物件,減少1;3.物件離開自己的作用域,如getrefcount(物件)方法,每次用完後,其對物件的那個引用就會被銷燬,減少1;4.物件從容器物件中刪除,或者容器物件被銷燬,減少1

(5)引用計數器用法:

import sys
class Person(object):
    pass
p = Person()
p1 = p
print(sys.getrefcount(p))
p2 = p1
print(sys.getrefcount(p))
p3 = p2
print(sys.getrefcount(p))
del p1
print(sys.getrefcount(p))

多一個引用,結果加1,銷燬一個引用,結果減少1

(6)引用計數器機制:利用引用計數器方法,在檢測到物件引用個數為0時,對普通的物件進行釋放記憶體的機制

關於迴圈引用問題

(1)迴圈引用即物件之間進行相互引用,出現迴圈引用後,利用上述引用計數機制無法對迴圈引用中的物件進行釋放空間,這就是迴圈引用問題

(2)迴圈引用形式:

class Person(object):
    pass
class Dog(object):
    pass
p = Person()
d = Dog()
p.pet = d
d.master = p

即物件p中的屬性引用d,而物件d中屬性同時來引用p,從而造成僅僅刪除p和d物件,也無法釋放其記憶體空間,因為他們依然在被引用。深入解釋就是,迴圈引用後,p和d被引用個數為2,刪除p和d物件後,兩者被引用個數變為1,並不是0,而python只有在檢查到一個物件的被引用個數為0時,才會自動釋放其記憶體,所以這裡無法釋放p和d的記憶體空間

關於垃圾回收(底層層面--原理)

(1)垃圾回收的作用:從經過引用計數器機制後還沒有被釋放掉記憶體的物件中,找到迴圈引用物件,並釋放掉其記憶體

(2)垃圾回收檢測流程:

一.任何找到迴圈引用並釋放記憶體:1.收集所有容器物件(迴圈引用只針對於容器物件,其他物件不會產生迴圈引用),使用雙向連結串列(可以看作一個集合)對這些物件進行引用;2.針對每一個容器物件,使用變數gc_refs來記錄當前對應的應用個數;3.對於每個容器物件,找到其正在引用的其他容器物件,並將這個被引用的容器物件引用計數減去1;4.經過步驟3後,檢查所有容器物件的引用計數,若為0,則證明該容器物件是由於迴圈引用存活下來的,並對其進行銷燬

二.如何提升查詢迴圈引用過程的效能:由一可知,迴圈引用查詢和銷燬過程非常繁瑣,要分別處理每一個容器物件,所以python考慮一種改善效能的做法,即分代回收。首先是一個假設--如果一個物件被檢測了10次還沒有被銷燬,就減少對其的檢測頻率;基於這個假設,提出一套機制,即分代回收機制。

通過這個機制,迴圈引用處理過程就會得到很大的效能提升

關於垃圾回收時機(應用層面--重點)

(1)自動回收:

(2)手動回收:這裡要使用gc模組中的collect()方法,使得執行這個方法時執行分代回收機制

import objgraph
import gc
import sys
class Person(object):
    pass
class Dog(object):
    pass
p = Person()
d = Dog()
p.pet = d
d.master = p
del p
del d
gc.collect()
print(objgraph.count("Person"))
print(objgraph.count("Dog"))

其中objgraph模組的count()方法是記錄當前類產生的例項物件的個數

關於記憶體管理機制的總結(重點)

綜上所述,python的記憶體管理機制就是引用計數器機制和垃圾回收機制的混合機制