內(nèi)存管理對于編寫出高效率的Windows程序是非常重要的,這是因為Windows是多任務(wù)系統(tǒng),它的內(nèi)存管理和單任務(wù)的DOS相比有很大的差異。那么python如何進行內(nèi)存管理呢?一起來了解下吧:
?
python如何進行內(nèi)存管理
?
?
一、對象的引用計數(shù)機制
?
python內(nèi)部使用引用計數(shù),來保持追蹤內(nèi)存中的對象,所有對象都有引用計數(shù)?
?
引用計數(shù)增加的情況:?
?
1. 一個對象分配一個新名稱?
?
2. 將其放入一個容器中?
?
引用計數(shù)減少的情況:?
?
1. 使用del語句對對象別名顯示的銷毀?
?
2. 引用超出作用域或被重新賦值?
?
sys.getrefcount()函數(shù)可以獲得對象的當(dāng)前引用計數(shù)?
?
多數(shù)情況下,引用計數(shù)比你猜測的要大得多。對于不可變數(shù)據(jù)(如數(shù)字和字符串),解釋器會在程序的不同部分共享內(nèi)存,以便節(jié)約內(nèi)存。
?
二、垃圾回收
?
當(dāng)一個對象的引用計數(shù)歸零時,它將被垃圾收集機制處理掉。
?
當(dāng)兩個對象a 和b 相互引用時,del語句可以減少a和b的引用次數(shù),并銷毀用于引用底層對象的名稱。然而由于每個對象都包含一個對其他對象的應(yīng)用,因此引用計數(shù)不會歸零,對象也不會銷毀。(從而導(dǎo)致內(nèi)存泄漏)。為解決這一問題,解釋器會定期執(zhí)行一個循環(huán)檢測器,搜索不可訪問對象的循環(huán)并刪除它們。
?
三、內(nèi)存池機制
?
python提供了對內(nèi)存的垃圾收集機制,但是它將不用的內(nèi)存放到內(nèi)存池而不是返回給操作系統(tǒng)。?
?
1. Pymalloc機制。為了加速python的執(zhí)行效率,python引入了一個內(nèi)存池機制,用于管理對小塊內(nèi)存的申請和釋放。?
?
2. python中所有小于256個字節(jié)的對象都使用pymalloc實現(xiàn)的分配器,而大的對象則使用系統(tǒng)的malloc。?
?
3. 對于python對象,如整數(shù),浮點數(shù)和list,都有其獨立的私有內(nèi)存池,對象間不共享它們的內(nèi)存池。也就是說如果你分配又釋放了大量的整數(shù),用于緩存這些整數(shù)的內(nèi)存就不能再分配給浮點數(shù)。
?
python怎么內(nèi)存管理
?
內(nèi)存管理
?
包括:
?
變量無須事先聲明
?
變量無須指定類型
?
不用關(guān)心內(nèi)存管理
?
變量名會被"回收"
?
del 語句能夠直接釋放資源
?
變量定義
?
python中, 變量在*次被賦值時自動聲明, 和其它語言一樣, 變量只有被創(chuàng)建和賦值后才能被使用
?
動態(tài)類型
?
變量名無須事先聲明, 也無須類型聲明
?
對象的類型和內(nèi)存占用都是運行時確定的
?
內(nèi)存分配
?
python解釋器會自動進行內(nèi)存管理, 不用開發(fā)人員去關(guān)心
?
引用計數(shù)
?
要保持追蹤內(nèi)存中的狀態(tài), python使用了引用計數(shù), 就是python內(nèi)部記錄著所有使用中的對象各有多少引用.
?
一個內(nèi)部跟蹤變量, 稱為一個引用計數(shù)器, 至于每個對象各有多少引用, 簡稱引用計數(shù), 當(dāng)對象被創(chuàng)建時, 就創(chuàng)建了一個引用計數(shù), 當(dāng)這個對象不再需要時, 也就是說, 這個對象的引用計數(shù)變?yōu)?時, 它被垃圾回收
?
增加引用計數(shù)
?
當(dāng)對象被創(chuàng)建賦值給變量時, 該對象的引用計數(shù)就被設(shè)置為1
?
當(dāng)同一個對象又被賦值給其他變量時, 或作為參數(shù)傳遞給函數(shù), 方法或類實例時, 或者被賦值為一個窗口對象的成員時, 該對象的一個新的引用, 或者作為別名, 就被創(chuàng)建.
?
減少引用計數(shù)
?
當(dāng)對象的引用被銷毀時, 引用計數(shù)會減少, 明顯的例子就是當(dāng)引用離開其作用范圍時, 這種情況最經(jīng)常出現(xiàn)在函數(shù)運行結(jié)束時, 所有局部變量都被自動銷毀, 對象的引用計數(shù)也就減少
?
垃圾收集
?
不再被使用的內(nèi)存會被一種稱為垃圾收集的機制釋放
?
注: 解釋器跟蹤對象的引用計數(shù), 垃圾回收機制負責(zé)釋放內(nèi)存, 垃圾收集器是一塊獨立代碼, 它用來尋找引用計數(shù)為0的對象, 它也負責(zé)檢查雖然引用計數(shù)大于0但是也應(yīng)該被銷毀的對象
?
引用語義: python中在變量里保存值(對象)的引用, 采用這種方式, 變量所需的存儲空間大小一致, 因為其只需要保存一個引用
?
值語義變量的值直接保存在變量的存儲區(qū)里, 這樣一個整數(shù)類型的變量就需要保存一個整數(shù)所需的空間, 一個浮點數(shù)變量就需要足夠的空間存儲一個浮點數(shù). C中就是值語義
?
python的內(nèi)存管理機制
?
先從較淺的層面來說,Python的內(nèi)存管理機制可以從三個方面來講
?
(1)垃圾回收
?
(2)引用計數(shù)
?
(3)內(nèi)存池機制
?
?
一、垃圾回收:
?
python不像C++,Java等語言一樣,他們可以不用事先聲明變量類型而直接對變量進行賦值。對Python語言來講,對象的類型和內(nèi)存都是在運行時確定的。這也是為什么我們稱Python語言為動態(tài)類型的原因(這里我們把動態(tài)類型可以簡單的歸結(jié)為對變量內(nèi)存地址的分配是在運行時自動判斷變量類型并對變量進行賦值)。
?
二、引用計數(shù):
?
Python采用了類似Windows內(nèi)核對象一樣的方式來對內(nèi)存進行管理。每一個對象,都維護這一個對指向該對對象的引用的計數(shù)。如圖所示(圖片來自Python核心編程)
?
、
?
x = 3.14
?
y = x
?
我們首先創(chuàng)建了一個對象3.14, 然后將這個浮點數(shù)對象的引用賦值給x,因為x是*個引用,因此,這個浮點數(shù)對象的引用計數(shù)為1. 語句y = x創(chuàng)建了一個指向同一個對象的引用別名y,我們發(fā)現(xiàn),并沒有為Y創(chuàng)建一個新的對象,而是將Y也指向了x指向的浮點數(shù)對象,使其引用計數(shù)為2.
?
python內(nèi)存管理的方法
?
1)動態(tài)類型
?
1.1)核心思想
?
python中"一切皆對象".作為"動態(tài)語言",python遵循"對象與引用分離"的核心思想.
?
1.2)一切皆對象
?
常見的變量,如整數(shù)、字符串、列表等,在python中一切皆為對象
?
a = 1
?
整數(shù)1為一個對象,是儲存在內(nèi)存中的實體.
?
對象名a為一個引用,我們不能直接接觸到"對象實體",只能通過引用指向去訪問,引用可以隨時指向一個新的對象.
?
1.3)賦值操作:可變對象、不可變對象
?
不可變數(shù)據(jù)對象:不能改變對象本身,只能改變引用的指向;如整形、字符串、元祖等
?
a = 5
?
b = a
?
a = a + 2
?
解析:此時a = 7,b = 5.驗證了不可變對象只能改變引用的指向,各個引用相互獨立,互不影響.
?
可變數(shù)據(jù)對象:引用其元素(類似于L[0]),改變對象的本身;如列表,字典等
?
L1 = [1,2,3]
?
L2 = L1
?
L1[0] = 100
?
解析:此時L1 = L2 = [100,2,3].驗證了可變對象可以通過引用其元素,改變對象本身
?
1.4)從動態(tài)類型看函數(shù)的參數(shù)傳遞
?
def f(x):
?
? ? x = 100
?
? ? print x
?
a = 1
?
f(a)
?
print a
?
解析:參數(shù)x是一個新的引用,指向a所指的對象.此處為不可變對象,引用a和x之間是相互獨立的.參數(shù)x的操作不會影響引用a.
?
def f(x):
?
? ? x[0] = 100
?
? ? print x
?
a = [1,2,3]
?
f(a)
?
print a
?
解析:參照上一個例子,此處為可變對象傳參,可以通過引用其元素改變對象本身.所以此處a和x都為[100,2,3]
?
1.5)垃圾回收
?
python采取了一種簡單的垃圾回收機制:即引用計數(shù)(from sys import getrefcount()).垃圾回收時,python不能進行其他任務(wù),頻繁的垃圾回收會大大降低python的工作效率.因此,python會在特定的情況下,自動啟動垃圾回收機制.
?
通過gc模塊查看垃圾回收閥值.
?
import gc
?
print gc.get_threshold()
?
輸出(700,10,10)
?
解析:700是垃圾回收的閥值:內(nèi)存中分配對象的次數(shù)-取消分配對象的次數(shù)=700;可以通過set.threshold()設(shè)置.
?
手動啟動垃圾回收機制:gc.collect()
?
1.6)分代回收
?
存活越久的對象,處于信任和效率,越不可能在后面的程序中變?yōu)槔?所以減少垃圾回收掃描他們的頻率.
?
python將所有的對象分為0,1,2三代.所有新建的對象都是0帶對象.當(dāng)經(jīng)過某一次垃圾回收,依然存活,那么它就被歸入下一代對象.
?
參考1.5,輸出中包含2個10,分別代表:每10次0代對象垃圾回收,會進行1次1代對象垃圾回收;每10次1代對象垃圾回收,會進行1次2代對象垃圾回收
?
我們在平時應(yīng)該避免對2代對象頻繁掃描:gc.set_threshold(700,10,20)
?