python記憶體管理機制

2022-02-28 05:17:31 字數 2663 閱讀 5946

a = 1
整數1為乙個物件。而a是乙個引用。利用賦值語句,引用a指向物件1。

在python中,整數和短小的字元,python都會快取這些物件,以便重複使用。當我們建立多個等於1的引用時,實際上是讓所有這些引用指向同乙個物件。

a = 1

b = 1

print(id(a))

print(id(b))

在python中,每個物件都有存有指向該物件的引用總數,即引用計數(reference count)。

我們可以使用sys包中的getrefcount(),來檢視某個物件的引用計數。需要注意的是,當使用某個引用作為引數,傳遞給getrefcount()時,引數實際上建立了乙個臨時的引用。因此,getrefcount()所得到的結果,會比期望的多1。

from sys import getrefcount

a = [1, 2, 3]

print(getrefcount(a))

b = a

print(getrefcount(b))

總結一下物件會在一下情況下引用計數加1:

引用計數減少情況

從基本原理上,當python的某個物件的引用計數降為0時,說明沒有任何引用指向該物件,該物件就成為要被**的垃圾了。比如某個新建物件,它被分配給某個引用,物件的引用計數變為1。如果引用被刪除,物件的引用計數為0,那麼該物件就可以被垃圾**。

a = [1, 2, 3]

del a

del a後,已經沒有任何引用指向之前建立的[1, 2, 3]這個表。使用者不可能通過任何方式接觸或者動用這個物件。這個物件如果繼續待在記憶體裡,浪費記憶體空間。當垃圾**啟動時,python掃瞄到這個引用計數為0的物件,就將它所佔據的記憶體清空。

然而,垃圾**是個昂貴而費力的事情。垃圾**時,python不能進行其它的任務。頻繁的垃圾**將大大降低python的工作效率。如果記憶體中的物件不多,就沒有必要總啟動垃圾**。所以,python只會在特定條件下,自動啟動垃圾**。當python執行時,會記錄其中分配物件(object allocation)和取消分配物件(object deallocation)的次數。當兩者的差值高於某個閾值時,垃圾**才會啟動。

我們可以通過gc模組的get_threshold()方法,檢視該閾值:

import gc

print(gc.get_threshold())

返回(700, 10, 10),後面的兩個10是與分代**相關的閾值,後面可以看到。700即是垃圾**啟動的閾值。可以通過gc中的set_threshold()方法重新設定。

我們也可以手動啟動垃圾**,即使用gc.collect()。

python同時採用了分代(generation)**的策略。這一策略的基本假設是,存活時間越久的物件,越不可能在後面的程式中變成垃圾。我們的程式往往會產生大量的物件,許多物件很快產生和消失,但也有一些物件長期被使用。出於信任和效率,對於這樣一些「長壽」物件,我們相信它們的用處,所以減少在垃圾**中掃瞄它們的頻率。

python將所有的物件分為0,1,2三代。所有的新建物件都是0代物件。當某一代物件經歷過垃圾**,依然存活,那麼它就被歸入下一代物件。垃圾**啟動時,一定會掃瞄所有的0代物件。如果0代經過一定次數垃圾**,那麼就啟動對0代和1代的掃瞄清理。當1代也經歷了一定次數的垃圾**後,那麼會啟動對0,1,2,即對所有物件進行掃瞄。

這兩個次數即上面get_threshold()返回的(700, 10, 10)返回的兩個10。也就是說,每10次0代垃圾**,會配合1次1代的垃圾**;而每10次1代的垃圾**,才會有1次的2代垃圾**。

同樣可以用set_threshold()來調整,比如對2代物件進行更頻繁的掃瞄。

import gc

gc.set_threshold(700, 10, 5)

兩個物件可能相互引用,從而構成所謂的引用環(reference cycle)。

a = 

print(getrefcount(a))

即使是乙個物件,只需要自己引用自己,也能構成引用環。

a = 

print(getrefcount(a))

引用環會給垃圾**機制帶來很大的麻煩,引用環的存在會給垃圾**機制帶來很大的困難。這些引用環可能構成無法使用,但引用計數不為0的一些物件。

a = 

b = [a]

del a

del b

上面我們先建立了兩個表物件,並引用對方,構成乙個引用環。刪除了a,b引用之後,這兩個物件不可能再從程式中呼叫,就沒有什麼用處了。但是由於引用環的存在,這兩個物件的引用計數都沒有降到0,不會被垃圾**。

為了**這樣的引用環,python複製每個物件的引用計數,可以記為gc_ref。假設,每個物件i,該計數為gc_ref_i。python會遍歷所有的物件i。對於每個物件i引用的物件j,將相應的gc_ref_j減1。

在結束遍歷後,gc_ref不為0的物件,和這些物件引用的物件,以及繼續更下游引用的物件,需要被保留。而其它的物件則被垃圾**

Python記憶體管理機制

一 python記憶體 因為要呼叫while迴圈,迴圈內有temp變數,不清楚python是否會在每一輪迴圈結束後自動釋放temp記憶體空間,做了乙個記憶體測試,發現無論temp none,還是del temp,只能銷毀變數,無法完全釋放記憶體空間。注 紅色部分標出相同記憶體id。python vi...

python記憶體管理機制

1.引用計數 當乙個python物件被引用時 其引用計數增加 1 當其不再被變數引用時 引用計數減 1 當物件引用計數等於 0 時,物件被刪除 引用計數是一種非常高效的記憶體管理機制 2.垃圾 垃圾 機制 引用計數 標記清除 分帶 引用計數 引用計數也是一種垃圾收集機制,而且也是一種最直觀,最簡單的...

Python記憶體管理機制

由於python中萬物皆物件,所以python的儲存問題是物件的儲存問題,並且對於每個物件,python會分配一塊記憶體空間去儲存它 注意 變數名沒有型別,型別屬於物件 因為變數引用物件,所以型別隨物件 變數引用什麼型別的物件,變數就是什麼型別的。a 123 b a print id a print...