1. 程式人生 > >python記憶體管理機制

python記憶體管理機制

python的記憶體管理機制:引用計數、垃圾回收、記憶體池機制

一 變數和物件

1、Python快取了整數和短字串,因此每個物件在記憶體中只存有一份,引用所指物件就是相同的,即使使用賦值語句,也只是創造新的引用,而不是物件本身;

2、Python沒有快取長字串、列表及其他物件,可以由多個相同的物件,可以使用賦值語句創建出新的物件。

附:

id()是python的內建函式,用於返回物件的身份,即物件的記憶體地址。

is進行引用所指判斷,is是用來判斷兩個引用所指的物件是否相同。

二  引用計數

在Python中,每個物件都有指向該物件的引用總數---引用計數;檢視物件的引用計數:sys.getrefcount()

1 普通引用 :當使用某個引用作為引數,傳遞給getrefcount()時,引數實際上建立了一個臨時的引用。因此,getrefcount()所得到的結果,會比期望的多1。

In [2]: import sys

In [3]: a=[1,2,3]
In [4]: getrefcount(a)
Out[4]: 2

In [5]: b=a
In [6]: getrefcount(a)
Out[6]: 3
In [7]: getrefcount(b)
Out[7]: 3

2 容器物件:容器物件中包含的並不是元素物件本身,是指向各個元素物件的引用。容器作為二層引用,一一對應指向各元素的物件。b引用/a引用指向——容器物件([0] [1] [2] ...)指向——元素物件(1,2,3,4...)

In [12]: a=[1,2,3,4,5]
In [13]: b=a

In [14]: a is b
Out[14]: True

In [15]: a[0]=6   
In [16]: a
Out[16]: [6, 2, 3, 4, 5]

In [17]: a is b
Out[17]: True

In [18]: b
Out[18]: [6, 2, 3, 4, 5]

3 引用計數增加 : getrefcount(123)

  • 物件被建立 a = 123
  • 另外的別人被建立 b=a
  • 作為容器物件的一個元素  c = [1,12,123]
  • 被作為引數傳遞給函式:foo(x)

4、引用計數減少

  • 物件的別名被顯式的銷燬  del b
  •  物件的一個別名被賦值給其他物件 a = 456
  • 物件從一個視窗物件中移除,或,視窗物件本身被銷燬  c.remove(123)
  • 一個本地引用離開了它的作用域,比如上面的foo(x)函式結束時,x指向的物件引用減1。

三 垃圾回收

當Python中的物件越來越多,佔據越來越大的記憶體,啟動垃圾回收(garbage collection),將沒用的物件清除。

1、原理 a = [321,123]  del a

當Python的某個物件的引用計數降為0時,說明沒有任何引用指向該物件,該物件就成為要被回收的垃圾。比如某個新建物件,被分配給某個引用,物件的引用計數變為1。如果引用被刪除,物件的引用計數為0,那麼該物件就可以被垃圾回收。

2、解析del

del a後,已經沒有任何引用指向之前建立的[321,123],該表引用計數變為0,使用者不可能通過任何方式接觸或者動用這個物件,當垃圾回收啟動時,Python掃描到這個引用計數為0的物件,就將它所佔據的記憶體清空。

3、注意

  • 垃圾回收時,Python不能進行其它的任務,頻繁的垃圾回收將大大降低Python的工作效率;
  • Python只會在特定條件下,自動啟動垃圾回收(垃圾物件少就沒必要回收);
  • 當Python執行時,會記錄其中分配物件(object allocation)和取消分配物件(object deallocation)的次數。當兩者的差值高於某個閾值時,垃圾回收才會啟動。
  • In [93]: import gc
    
    In [94]: gc.get_threshold()  #gc模組中檢視閾值的方法
    Out[94]: (700, 10, 10)

      700即是垃圾回收啟動的閾值;每10次0代垃圾回收,會配合1次1代的垃圾回收;而每10次1代的垃圾回收,才會有1次的2代垃圾回收;

  • gc.collect() 手動啟動垃圾回收

4 分代回收

Python將所有的物件分為0,1,2三代;所有的新建物件都是0代物件;當某一代物件經歷過垃圾回收,依然存活,就被歸入下一代物件。

四 記憶體池機制

Python中有分為大記憶體和小記憶體:(256K為界限分大小記憶體)

1、大記憶體使用malloc進行分配

2、小記憶體使用記憶體池進行分配

3、Python的記憶體池(金字塔)

  第3層:最上層,使用者對Python物件的直接操作

  第1層和第2層:記憶體池,有Python的介面函式PyMem_Malloc實現-----若請求分配的記憶體在1~256位元組之間就使用記憶體池管理系統進行分配,呼叫malloc函式分配記憶體,但是每次只會分配一塊大小為256K的大塊記憶體,不會呼叫free函式釋放記憶體,將該記憶體塊留在記憶體池中以便下次使用。

  第0層:大記憶體-----若請求分配的記憶體大於256K,malloc函式分配記憶體,free函式釋放記憶體。

  第-1,-2層:作業系統進行操作