Python是如何實(shí)現(xiàn)內(nèi)存管理的?

點(diǎn)評:當(dāng)面試官問到這個問題的時候胜卤,一個展示自己的機(jī)會就擺在面前了疆导。你要先反問面試官:“你說的是官方的CPython解釋器嗎?”葛躏。這個反問可以展示出你了解過Python解釋器的不同的實(shí)現(xiàn)版本澈段,而且你也知道面試官想問的是CPython。當(dāng)然舰攒,很多面試官對不同的Python解釋器底層實(shí)現(xiàn)到底有什么差別也沒有概念败富。所以,千萬不要覺得面試官一定比你強(qiáng)摩窃,懷揣著這份自信可以讓你更好的完成面試囤耳。

Python提供了自動化的內(nèi)存管理,也就是說內(nèi)存空間的分配與釋放都是由Python解釋器在運(yùn)行時自動進(jìn)行的偶芍,自動管理內(nèi)存功能極大的減輕程序員的工作負(fù)擔(dān)充择,也能夠幫助程序員在一定程度上解決內(nèi)存泄露的問題。以CPython解釋器為例匪蟀,它的內(nèi)存管理有三個關(guān)鍵點(diǎn):引用計(jì)數(shù)椎麦、標(biāo)記清理、分代收集材彪。

引用計(jì)數(shù):對于CPython解釋器來說观挎,Python中的每一個對象其實(shí)就是PyObject結(jié)構(gòu)體,它的內(nèi)部有一個名為ob_refcnt 的引用計(jì)數(shù)器成員變量段化。程序在運(yùn)行的過程中ob_refcnt的值會被更新并藉此來反映引用有多少個變量引用到該對象嘁捷。當(dāng)對象的引用計(jì)數(shù)值為0時,它的內(nèi)存就會被釋放掉显熏。

typedef struct _object {
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
} PyObject;

以下情況會導(dǎo)致引用計(jì)數(shù)加1:
對象被創(chuàng)建
對象被引用
對象作為參數(shù)傳入到一個函數(shù)中
對象作為元素存儲到一個容器中

以下情況會導(dǎo)致引用計(jì)數(shù)減1:
用del語句顯示刪除對象引用
對象引用被重新賦值其他對象
一個對象離開它所在的作用域
持有該對象的容器自身被銷毀
持有該對象的容器刪除該對象

可以通過sys模塊的getrefcount函數(shù)來獲得對象的引用計(jì)數(shù)雄嚣。引用計(jì)數(shù)的內(nèi)存管理方式在遇到循環(huán)引用的時候就會出現(xiàn)致命傷,因此需要其他的垃圾回收算法對其進(jìn)行補(bǔ)充。

標(biāo)記清理:CPython使用了“標(biāo)記-清理”(Mark and Sweep)算法解決容器類型可能產(chǎn)生的循環(huán)引用問題缓升。
該算法在垃圾回收時分為兩個階段:標(biāo)記階段鼓鲁,遍歷所有的對象,如果對象是可達(dá)的(被其他對象引用)港谊,那么就標(biāo)記該對象為可達(dá)骇吭;清除階段,再次遍歷對象歧寺,如果發(fā)現(xiàn)某個對象沒有標(biāo)記為可達(dá)燥狰,則就將其回收。
CPython底層維護(hù)了兩個雙端鏈表斜筐,一個鏈表存放著需要被掃描的容器對象(姑且稱之為鏈表A)龙致,另一個鏈表存放著臨時不可達(dá)對象(姑且稱之為鏈表B)。為了實(shí)現(xiàn)“標(biāo)記-清理”算法奴艾,鏈表中的每個節(jié)點(diǎn)除了有記錄當(dāng)前引用計(jì)數(shù)的ref_count變量外净当,還有一個gc_ref變量,這個gc_ref是ref_count的一個副本蕴潦,所以初始值為ref_count的大小像啼。執(zhí)行垃圾回收時,首先遍歷鏈表A中的節(jié)點(diǎn)潭苞,并且將當(dāng)前對象所引用的所有對象的gc_ref減1忽冻,這一步主要作用是解除循環(huán)引用對引用計(jì)數(shù)的影響。再次遍歷鏈表A中的節(jié)點(diǎn)此疹,如果節(jié)點(diǎn)的gc_ref值為0僧诚,那么這個對象就被標(biāo)記為“暫時不可達(dá)”(GC_TENTATIVELY_UNREACHABLE)并被移動到鏈表B中;如果節(jié)點(diǎn)的gc_ref不為0蝗碎,那么這個對象就會被標(biāo)記為“可達(dá)“(GC_REACHABLE)湖笨,對于”可達(dá)“對象,還要遞歸的將該節(jié)點(diǎn)可以到達(dá)的節(jié)點(diǎn)標(biāo)記為”可達(dá)“蹦骑;鏈表B中被標(biāo)記為”可達(dá)“的節(jié)點(diǎn)要重新放回到鏈表A中慈省。在兩次遍歷之后,鏈表B中的節(jié)點(diǎn)就是需要釋放內(nèi)存的節(jié)點(diǎn)眠菇。

分代回收:在循環(huán)引用對象的回收中边败,整個應(yīng)用程序會被暫停,為了減少應(yīng)用程序暫停的時間捎废,Python 通過分代回收(空間換時間)的方法提高垃圾回收效率笑窜。分代回收的基本思想是:對象存在的時間越長,是垃圾的可能性就越小登疗,應(yīng)該盡量不對這樣的對象進(jìn)行垃圾回收排截。CPython將對象分為三種世代分別記為0、1、2匾寝,每一個新生對象都在第0代中搬葬,如果該對象在一輪垃圾回收掃描中存活下來荷腊,那么它將被移到第1代中艳悔,存在于第1代的對象將較少的被垃圾回收掃描到;如果在對第1代進(jìn)行垃圾回收掃描時女仰,這個對象又存活下來猜年,那么它將被移至第2代中,在那里它被垃圾回收掃描的次數(shù)將會更少疾忍。分代回收掃描的門限值可以通過gc模塊的get_threshold函數(shù)來獲得乔外,該函數(shù)返回一個三元組,分別表示多少次內(nèi)存分配操作后會執(zhí)行0代垃圾回收一罩,多少次0代垃圾回收后會執(zhí)行1代垃圾回收杨幼,多少次1代垃圾回收后會執(zhí)行2代垃圾回收。需要說明的是聂渊,如果執(zhí)行一次2代垃圾回收差购,那么比它年輕的代都要執(zhí)行垃圾回收。如果想修改這幾個門限值汉嗽,可以通過gc模塊的set_threshold函數(shù)來做到欲逃。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市饼暑,隨后出現(xiàn)的幾起案子稳析,更是在濱河造成了極大的恐慌,老刑警劉巖弓叛,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件彰居,死亡現(xiàn)場離奇詭異,居然都是意外死亡撰筷,警方通過查閱死者的電腦和手機(jī)陈惰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來闭专,“玉大人奴潘,你說我怎么就攤上這事∮岸ぃ” “怎么了画髓?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長平委。 經(jīng)常有香客問我奈虾,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任肉微,我火速辦了婚禮匾鸥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘碉纳。我一直安慰自己勿负,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布劳曹。 她就那樣靜靜地躺著奴愉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪铁孵。 梳的紋絲不亂的頭發(fā)上锭硼,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天,我揣著相機(jī)與錄音蜕劝,去河邊找鬼檀头。 笑死,一個胖子當(dāng)著我的面吹牛岖沛,可吹牛的內(nèi)容都是我干的暑始。 我是一名探鬼主播,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼烫止,長吁一口氣:“原來是場噩夢啊……” “哼蒋荚!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起馆蠕,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤期升,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后互躬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體播赁,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年吼渡,在試婚紗的時候發(fā)現(xiàn)自己被綠了容为。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,989評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡寺酪,死狀恐怖坎背,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情寄雀,我是刑警寧澤得滤,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站盒犹,受9級特大地震影響懂更,放射性物質(zhì)發(fā)生泄漏眨业。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一沮协、第九天 我趴在偏房一處隱蔽的房頂上張望龄捡。 院中可真熱鬧,春花似錦慷暂、人聲如沸聘殖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽就斤。三九已至悍募,卻和暖如春蘑辑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背坠宴。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工洋魂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人喜鼓。 一個月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓副砍,卻偏偏與公主長得像,于是被迫代替她去往敵國和親庄岖。 傳聞我的和親對象是個殘疾皇子豁翎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內(nèi)容