python是如何進行記憶體管理的

2022-03-22 21:18:49 字數 3263 閱讀 1320

一、python記憶體管理

這個問題需要從三個方面來說:

1)物件的引用計數機制(四增五減

2)垃圾**機制(手動自動,分代**

3)記憶體池機制(大m小p

1)物件的引用計數機制

要保持追蹤記憶體中的物件,python使用了引用計數這一簡單的技術。sys.getrefcount(a)可以檢視a物件的引用計數,但是比正常計數大1,因為呼叫函式的時候傳入a,這會讓a的引用計數+1

a)增加引用計數

b)

減少引用計數

c)引用計數例子,加深理解

id()獲取物件的記憶體位址

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

#is用於判斷兩個引用所指的物件是否相同。

a = 1

b = 1

a is b

#true

print(id(a))

#505348560

print(id(b))

#505348560

a = 'good'

b = 'good'

a is b

#true

讓我們來看看較長的字串:

a = "very good morning"

b = "very good morning"

id(a)

#57960680

id(b)

#57960968

a is b

#false

sys.getrefcount()來獲取物件的引用計數:

import sys

a = [1 ,2, 3]

print( sys.getrefcount(a) )

#2b = a

print( sys.getrefcount(a) )

#3

2)垃圾**機制

吃太多,總會變胖,python也是這樣。當python中的物件越來越多,它們將佔據越來越大的記憶體。不過你不用太擔心python的體形,它會在適當的時候「**」,啟動垃圾**(garbage collection),將沒用的物件清除

從基本原理上,當python的某個物件的引用計數降為0時,說明沒有任何引用指向該物件,該物件就成為要被**的垃圾了

比如某個新建物件,它被分配給某個引用,物件的引用計數變為1。如果引用被刪除,物件的引用計數為0,那麼該物件就可以被垃圾**。比如下面的表

a = [1, 2, 3]

sys.getrefcount(a)

#2del a

del a後,已經沒有任何引用指向之前建立的[1, 2, 3]這個表。這個物件如果繼續待在記憶體裡,就成了不健康的脂肪。當垃圾**啟動時,python掃瞄到這個引用計數為0的物件,就將它所佔據的記憶體清空

然而,**是個昂貴而費力的事情。垃圾**時,python不能進行其它的任務。頻繁的垃圾**將大大降低python的工作效率。如果記憶體中的物件不多,就沒有必要總啟動垃圾**

所以,python只會在特定條件下,自動啟動垃圾**。當python執行時,會記錄其中分配物件(object allocation)和取消分配物件(object deallocation)的次數。當兩者的差值高於某個閾值時,垃圾**才會啟動

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

import gc

gc.get_threshold()

#(700, 10, 10)

返回(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)

3)記憶體池機制

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

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

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

python中的記憶體管理機制都有兩套實現,一套是針對小物件,就是大小小於256k時,pymalloc會在記憶體池中申請記憶體空間;當大於256k時,則會直接執行系統的malloc的行為來申請記憶體空間 

Python是如何進行記憶體管理

三個方面 一物件的引用計數機制,二垃圾 機制,三記憶體池機制 一 物件的引用計數機制 python內部使用引用計數,來保持追蹤記憶體中的物件,所有物件都有引用計數。引用計數增加的情況 1,乙個物件分配乙個新名稱 2,將其放入乙個容器中 如列表 元組或字典 引用計數減少的情況 1,使用del語句對物件...

Python是如何進行記憶體管理的?

python引用了乙個記憶體池 memory pool 機制,即pymalloc機制 malloc n.分配記憶體 用於管理對小塊記憶體的申請和釋放 記憶體池 memory pool 的概念 當 建立大量消耗小記憶體的物件時,頻繁呼叫new malloc會導致大量的記憶體碎片,致使效率降低。記憶體池...

python是如何進行記憶體管理的

python引入了乙個機制 引用計數。python內部使用引用計數,來保持追蹤記憶體中的物件,python內部記錄了物件有多少個引用,即引用計數,當物件被建立時就建立了乙個引用計數,當物件不再需要時,這個物件的引用計數為0時,它被垃圾 總結一下物件會在一下情況下引用計數加1 1.物件被建立 x 4 ...