![【移動應(yīng)用開發(fā)技術(shù)】Python垃圾回收是如何現(xiàn)的_第1頁](http://file4.renrendoc.com/view/e10b0a1dfe3d44829dc2deb5cb497bd2/e10b0a1dfe3d44829dc2deb5cb497bd21.gif)
![【移動應(yīng)用開發(fā)技術(shù)】Python垃圾回收是如何現(xiàn)的_第2頁](http://file4.renrendoc.com/view/e10b0a1dfe3d44829dc2deb5cb497bd2/e10b0a1dfe3d44829dc2deb5cb497bd22.gif)
![【移動應(yīng)用開發(fā)技術(shù)】Python垃圾回收是如何現(xiàn)的_第3頁](http://file4.renrendoc.com/view/e10b0a1dfe3d44829dc2deb5cb497bd2/e10b0a1dfe3d44829dc2deb5cb497bd23.gif)
![【移動應(yīng)用開發(fā)技術(shù)】Python垃圾回收是如何現(xiàn)的_第4頁](http://file4.renrendoc.com/view/e10b0a1dfe3d44829dc2deb5cb497bd2/e10b0a1dfe3d44829dc2deb5cb497bd24.gif)
![【移動應(yīng)用開發(fā)技術(shù)】Python垃圾回收是如何現(xiàn)的_第5頁](http://file4.renrendoc.com/view/e10b0a1dfe3d44829dc2deb5cb497bd2/e10b0a1dfe3d44829dc2deb5cb497bd25.gif)
下載本文檔
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
【移動應(yīng)用開發(fā)技術(shù)】Python垃圾回收是如何現(xiàn)的
這篇文章主要講解了“Python垃圾回收是如何現(xiàn)的”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著在下的思路慢慢深入,一起來研究和學(xué)習(xí)“Python垃圾回收是如何現(xiàn)的”吧!垃圾回收(GC)大家應(yīng)該多多少少都了解過,什么是垃圾回收呢?垃圾回收GC的全拼是GarbageCollection,在維基百科的定義是:在計算機科學(xué)中,垃圾回收(英語:GarbageCollection,縮寫為GC)是一種自動的內(nèi)存管理機制。當(dāng)一個電腦上的動態(tài)內(nèi)存不再需要時,就應(yīng)該予以釋放,以讓出內(nèi)存,這種內(nèi)存資源管理,稱為垃圾回收。我們都知道在C/C++里用戶需要自己管理維護內(nèi)存,自己管理內(nèi)存是很自由,可以隨意申請、釋放內(nèi)存,但是極易會出現(xiàn)內(nèi)存泄露,懸空指針等問題;像現(xiàn)在的高級語言Java,Python等,都采用了垃圾回收機制,自動進行內(nèi)存管理,而垃圾回收機制專注于兩件事:①找到內(nèi)存中無用的垃圾資源。②清除這些垃圾資源并把內(nèi)存讓出來給其他對象使用。Python作為一門解釋型語言,因為簡單易懂的語法,我們可以直接對變量賦值,而不必聲明變量的類型,變量類型的確定、內(nèi)存空間的分配與釋放都是由Python解釋器在運行時自動進行的,我們不必關(guān)心;Python這一自動管理內(nèi)存的功能極大的減少了開發(fā)者的編碼負擔(dān),讓開發(fā)者專注于業(yè)務(wù)實現(xiàn),這也是成就Python自身的重要原因之一。接下來,我們就扒一扒Python的內(nèi)存管理。引用計數(shù)Python中一切皆對象,也就是說,在Python中你用到的一切變量,本質(zhì)上都是類對象。實際上每一個對象的核心就是一個**「結(jié)構(gòu)體PyObject」**,它的內(nèi)部有一個引用計數(shù)器ob_refcnt,程序在運行的過程中會實時的更新ob_refcnt的值,來反映引用當(dāng)前對象的名稱數(shù)量。當(dāng)某對象的引用計數(shù)值為0,說明這個對象變成了垃圾,那么它會被回收掉,它所用的內(nèi)存也會被立即釋放掉。typedef
struct
_object
{
int
ob_refcnt;//引用計數(shù)
struct
_typeobject
*ob_type;
}
PyObject;以下情況是導(dǎo)致引用計數(shù)加一的情況:①對象被創(chuàng)建,例如a=5②對象被引用,b=a③對象被作為參數(shù),傳入到一個函數(shù)中(要注意的是,在函數(shù)調(diào)用發(fā)生的時候,會產(chǎn)生額外的兩次引用,一次來自函數(shù)棧,另一個是函數(shù)參數(shù))④對象作為一個元素,存儲在容器中(例如存儲在列表中)下面的情況則會導(dǎo)致引用計數(shù)減一:①對象別名被顯示銷毀dela②對象別名被賦予新的對象③一個對象離開它的作用域④對象所在的容器被銷毀或者是從容器中刪除對象我們還可以通過sys包中的getrefcount()來獲取一個名稱所引用的對象當(dāng)前的引用計數(shù)(注意,這里getrefcount()本身會使得引用計數(shù)加一)import
sys
a
=
[1,
2,
3]
print(sys.getrefcount(a))
#
輸出為2,說明有兩次引用(一次來自a的定義,一次來自getrefcount)
def
func(a):
print(sys.getrefcount(a))
#
輸出為4,說明有四次引用(a的定義、Python的函數(shù)調(diào)用棧,函數(shù)參數(shù),和getrefcount)
func(a)
print(sys.getrefcount(a))
#
輸出為2,說明有兩次引用(一次來自a的定義,一次來自getrefcount),此時函數(shù)func調(diào)用已經(jīng)不存在下面從使用內(nèi)存的角度看一下:import
os
import
psutil
def
show_memory_info(hint):
"""
顯示當(dāng)前
python
程序占用的內(nèi)存大小
:param
hint:
:return:
"""
pid
=
os.getpid()
p
=
psutil.Process(pid)
info
=
p.memory_full_info()
memory
=
info.rss
/
1024
/
1024
print("{}
當(dāng)前進程的內(nèi)存使用:
{}
MB".format(hint,
memory))
def
func():
show_memory_info("初始")
a
=
[i
for
i
in
range(9999999)]
show_memory_info("創(chuàng)建a之后")
func()
show_memory_info("結(jié)束")輸出如下:初始當(dāng)前進程的內(nèi)存使用:12.125MB創(chuàng)建a之后當(dāng)前進程的內(nèi)存使用:205.15625MB結(jié)束當(dāng)前進程的內(nèi)存使用:12.87890625MB初始當(dāng)前進程的內(nèi)存使用:12.125MB創(chuàng)建a之后當(dāng)前進程的內(nèi)存使用:205.15625MB結(jié)束當(dāng)前進程的內(nèi)存使用:12.87890625MB可以看出,當(dāng)前進程初始的內(nèi)存使用為12.125MB,當(dāng)調(diào)用了函數(shù)func()創(chuàng)建列表a之后,內(nèi)存占用迅速增加到了205.15625MB,而在函數(shù)調(diào)用結(jié)束后,內(nèi)存則返回正常。這是因為,函數(shù)內(nèi)部聲明的列表a是局部變量,在函數(shù)返回后,局部變量的引用會注銷掉,此時列表a所指代對象的引用計數(shù)為0,Python便會執(zhí)行垃圾回收,因此之前占用的大量內(nèi)存就又回來了。循環(huán)引用何為循環(huán)引用?簡單來說就是兩個對象相互引用??聪旅嬉欢纬绦颍篸ef
func2():
show_memory_info("初始")
a
=
[i
for
i
in
range(10000000)]
b
=
[x
for
x
in
range(10000001,
20000000)]
a.append(b)
b.append(a)
show_memory_info("創(chuàng)建a,b之后")
func2()
show_memory_info("結(jié)束")輸出如下:初始當(dāng)前進程的內(nèi)存使用:12.14453125MB創(chuàng)建a,b之后當(dāng)前進程的內(nèi)存使用:396.6875MB結(jié)束當(dāng)前進程的內(nèi)存使用:396.96875MB初始當(dāng)前進程的內(nèi)存使用:12.14453125MB創(chuàng)建a,b之后當(dāng)前進程的內(nèi)存使用:396.6875MB結(jié)束當(dāng)前進程的內(nèi)存使用:396.96875MB可以看出,在程序中,a和b互相引用,并且作為局部變量在函數(shù)func2調(diào)用結(jié)束后,a和b從程序意義上已經(jīng)不存在,但從輸出結(jié)果中看到,依然有內(nèi)存占用,這是為什么呢?因為互相引用導(dǎo)致它們的引用數(shù)都不為0。如果在生產(chǎn)環(huán)境下出現(xiàn)了循環(huán)引用,又沒有其他垃圾回收機制的情況下,經(jīng)過長時間運行后,程序所占用的內(nèi)存一定會變得越來越大,如果沒有被及時處理,一定會跑滿服務(wù)器的。如果不得不使用循環(huán)引用的話,我們可以顯式調(diào)用gc.collect()來啟動垃圾回收:def
func2():
show_memory_info("初始")
a
=
[i
for
i
in
range(10000000)]
b
=
[x
for
x
in
range(10000001,
20000000)]
a.append(b)
b.append(a)
show_memory_info("創(chuàng)建a,b之后")
func2()
gc.collect()
show_memory_info("結(jié)束")輸出如下:初始當(dāng)前進程的內(nèi)存使用:12.29296875MB創(chuàng)建a,b之后當(dāng)前進程的內(nèi)存使用:396.69140625MB結(jié)束當(dāng)前進程的內(nèi)存使用:12.95703125MB初始當(dāng)前進程的內(nèi)存使用:12.29296875MB創(chuàng)建a,b之后當(dāng)前進程的內(nèi)存使用:396.69140625MB結(jié)束當(dāng)前進程的內(nèi)存使用:12.95703125MB引用計數(shù)機制有高效、簡單、實時性(一旦為零就直接做掉)等優(yōu)點,一旦一個對象的引用計數(shù)歸零,內(nèi)存就直接釋放了。不用像其他機制等到特定時機。將垃圾回收隨機分配到運行的階段,處理回收內(nèi)存的時間分攤到了平時,正常程序的運行比較平穩(wěn)。但是,引用計數(shù)也存在著一些缺點,通常的缺點有:①邏輯雖然簡單,但維護起來有些麻煩。每個對象需要分配單獨的空間來統(tǒng)計引用計數(shù),并且需要對引用計數(shù)進行維護,這是需要消耗一下資源的。②循環(huán)引用。這將是引用計數(shù)機制的致命傷,引用計數(shù)對此是無解的,因此必須要使用其它的垃圾回收算法對其進行補充。事實上,Python使用標(biāo)記清除(mark-sweep)算法和分代收集(generational),來啟用針對循環(huán)引用的自動垃圾回收。標(biāo)記清除解除循環(huán)引用Python采用了標(biāo)記-清除(MarkandSweep)算法,解決容器對象可能產(chǎn)生的循環(huán)引用問題。(注意,只有容器類對象才有可能產(chǎn)生循環(huán)引用,比如列表、字典、用戶自定義類的對象、元組等。而像數(shù)字,字符串這類簡單類型不會出現(xiàn)循環(huán)引用。作為一種優(yōu)化策略,對于只包含簡單類型的元組也不在標(biāo)記清除算法的考慮之列)它分為兩個階段:第一階段是標(biāo)記階段,GC會把所有的活動對象打上標(biāo)記,第二階段是把那些沒有標(biāo)記的非活動對象進行回收。那么Python又是如何判斷什么樣的對象為非活動對象的呢?對于任何對象集合,我們先建個引用計數(shù)副本表,來存它們的引用計數(shù),然后把集合內(nèi)部的引用都解除掉(內(nèi)部引用是指這個集合中的某個對象引用了本集合內(nèi)部的另一個對象),解除的過程中在副本表減少引用計數(shù),解除掉所有的內(nèi)部引用后,在副本表引用計數(shù)依然不為0的,就是根集合,然后開始標(biāo)記過程,即從跟集合節(jié)點逐步恢復(fù)引用并增加副本表的引用計數(shù),最后副本表中引用計數(shù)為0的,就是垃圾對象了,我們就需要對它們進行垃圾回收。例如:上面這個集合中的節(jié)點有外部進來的連接(到a和到b),也有到外部的連接(c引用了外面某個對象),右邊是引用計數(shù)表,然后我們拆掉所有內(nèi)部連接:那么根集合就是a和b了,然后我們從a和b出發(fā)開始標(biāo)記并恢復(fù)引用計數(shù):從a和b出發(fā)可達的節(jié)點都被恢復(fù)了,引用計數(shù)還是0的就是這個集合內(nèi)部循環(huán)引用的垃圾(e和f),如果把所有對象看做一個集合,那么可以回收所有垃圾,也可以將所有對象劃分成一個個小的集合,分別回收小集合內(nèi)的垃圾。但是每次都需要遍歷圖,對于Python而言是一種巨大的性能浪費。分代回收分代回收是一種以空間換時間的操作方式,Python將內(nèi)存根據(jù)對象的存活時間劃分為不同的集合,每個集合稱為一個代,Python將內(nèi)存分為了3代,分別為年輕代(第0代)、中年代(第1代)、老年代(第2代)。它們對應(yīng)3個鏈表,它們的垃圾收集頻率隨對象的存活時間的增大而減小。新創(chuàng)建的對象都會分配在年輕代,
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度美發(fā)店員工社會保險合同
- 二零二五年度解除聘用合同及社會保險轉(zhuǎn)移協(xié)議
- 2025年度旅游項目終止及客戶權(quán)益保障合同
- 2025年中國明室沖洗牙片市場調(diào)查研究報告
- 2025年度員工培訓(xùn)費用補貼協(xié)議
- 2025年中國寢飾市場調(diào)查研究報告
- 2025年中國商場展示專柜市場調(diào)查研究報告
- 2025-2030年房車租賃及托管服務(wù)企業(yè)制定與實施新質(zhì)生產(chǎn)力戰(zhàn)略研究報告
- 2025-2030年政務(wù)服務(wù)材料審核機器人企業(yè)制定與實施新質(zhì)生產(chǎn)力戰(zhàn)略研究報告
- 2025至2031年中國露天潛孔鑿巖鉆車行業(yè)投資前景及策略咨詢研究報告
- 壓力性損傷護理質(zhì)控細則及集束化管理措施
- 《批判性思維原理和方法》全套教學(xué)課件
- 產(chǎn)后康復(fù)-腹直肌分離
- 丙烯-危險化學(xué)品安全周知卡
- 粉條加工廠建設(shè)項目可行性研究報告
- 《配電網(wǎng)設(shè)施可靠性評價指標(biāo)導(dǎo)則》
- 2024年國家電網(wǎng)招聘之通信類題庫附參考答案(考試直接用)
- CJJ 169-2012城鎮(zhèn)道路路面設(shè)計規(guī)范
- 食品企業(yè)日管控周排查月調(diào)度記錄及其報告格式參考
- 產(chǎn)品質(zhì)量法解讀課件1
- 第八單元金屬和金屬材料單元復(fù)習(xí)題-2023-2024學(xué)年九年級化學(xué)人教版下冊
評論
0/150
提交評論