偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Python 內(nèi)存管理的工作原理,你了解嗎?

譯文 精選
開(kāi)發(fā) 后端
Python 為開(kāi)發(fā)者提供了許多便利,其中最大的便利之一是其幾乎無(wú)憂的內(nèi)存管理。

Python 為開(kāi)發(fā)者提供了許多便利,其中最大的便利之一是其幾乎無(wú)憂的內(nèi)存管理。開(kāi)發(fā)者無(wú)需手動(dòng)為 Python 中的對(duì)象和數(shù)據(jù)結(jié)構(gòu)分配、跟蹤和釋放內(nèi)存。運(yùn)行時(shí)會(huì)為你完成所有這些工作,因此你可以專(zhuān)注于解決實(shí)際問(wèn)題,而不是爭(zhēng)論機(jī)器級(jí)細(xì)節(jié)。

盡管如此,即使是經(jīng)驗(yàn)不多的 Python 用戶,了解 Python 的垃圾收集和內(nèi)存管理是如何工作的也是有好處的。了解這些機(jī)制將幫助你避免更復(fù)雜的項(xiàng)目可能出現(xiàn)的性能問(wèn)題。你還可以使用 Python 的內(nèi)置工具來(lái)監(jiān)控程序的內(nèi)存管理行為。

Python如何管理內(nèi)存

每個(gè) Python 對(duì)象都有一個(gè)引用計(jì)數(shù),也稱(chēng)為引用計(jì)數(shù)。 refcount 是持有對(duì)給定對(duì)象的引用的其他對(duì)象總數(shù)的計(jì)數(shù)。當(dāng)你添加或刪除對(duì)對(duì)象的引用時(shí),數(shù)字會(huì)上升或下降。當(dāng)一個(gè)對(duì)象的引用計(jì)數(shù)變?yōu)榱銜r(shí),該對(duì)象將被釋放并釋放其內(nèi)存。

什么是參考?允許通過(guò)名稱(chēng)或通過(guò)另一個(gè)對(duì)象中的訪問(wèn)器訪問(wèn)對(duì)象的任何內(nèi)容。

這是一個(gè)簡(jiǎn)單的例子:

x = "Hello there"

當(dāng)我們向 Python 發(fā)出這個(gè)命令時(shí),引擎蓋下會(huì)發(fā)生兩件事:

  1. 該字符串"Hello there"作為 Python 對(duì)象創(chuàng)建并存儲(chǔ)在內(nèi)存中。
  2. 該名稱(chēng)x在本地命名空間中創(chuàng)建并指向該對(duì)象,這會(huì)將其引用計(jì)數(shù)增加 1 到 1。

如果我們說(shuō)y = x,那么引用計(jì)數(shù)將再次提高到 2。

每當(dāng)xandy超出范圍或從它們的命名空間中刪除時(shí),對(duì)于每個(gè)名稱(chēng),字符串的引用計(jì)數(shù)都會(huì)減少 1。一旦x和y都超出范圍或被刪除,字符串的引用計(jì)數(shù)變?yōu)?0 并被刪除。

現(xiàn)在,假設(shè)我們創(chuàng)建了一個(gè)包含字符串的列表,如下所示:

x = ["Hello there", 2, False]

字符串保留在內(nèi)存中,直到列表本身被刪除或包含字符串的元素從列表中刪除。這些操作中的任何一個(gè)都將導(dǎo)致唯一持有對(duì)字符串的引用的事物消失。

現(xiàn)在考慮這個(gè)例子:

x = "Hello there" y = [x]

如果我們從 中刪除第一個(gè)元素y,或者完全刪除列表y,則字符串仍在內(nèi)存中。這是因?yàn)槊Q(chēng)x包含對(duì)它的引用。

Python 中的引用循環(huán)

在大多數(shù)情況下,引用計(jì)數(shù)工作正常。但有時(shí)你會(huì)遇到兩個(gè)對(duì)象各自持有對(duì)彼此的引用的情況。這稱(chēng)為 參考周期。在這種情況下,對(duì)象的引用計(jì)數(shù)永遠(yuǎn)不會(huì)達(dá)到零,也永遠(yuǎn)不會(huì)從內(nèi)存中刪除。

這是一個(gè)人為的例子:

x = SomeClass()
y = SomeOtherClass()
x.item = y
y.item = x

由于x并y持有彼此的引用,因此它們永遠(yuǎn)不會(huì)從系統(tǒng)中刪除——即使沒(méi)有其他任何東西引用它們中的任何一個(gè)。

Python 自己的運(yùn)行時(shí)為對(duì)象生成引用循環(huán)實(shí)際上是相當(dāng)普遍的。一個(gè)示例是帶有包含對(duì)異常本身的引用的回溯對(duì)象的異常。

在Python的早期版本中,這是一個(gè)問(wèn)題。具有引用周期的對(duì)象可能會(huì)隨著時(shí)間的推移而累積,這對(duì)于長(zhǎng)時(shí)間運(yùn)行的應(yīng)用程序來(lái)說(shuō)是一個(gè)大問(wèn)題。但 Python 此后引入了循環(huán)檢測(cè)和垃圾收集系統(tǒng),用于管理引用循環(huán)。

Python 垃圾收集器 (gc)

Python 的垃圾收集器檢測(cè)具有引用周期的對(duì)象。它通過(guò)跟蹤作為“容器”的對(duì)象(例如列表、字典、自定義類(lèi)實(shí)例)并確定其中的哪些對(duì)象無(wú)法在其他任何地方訪問(wèn)來(lái)實(shí)現(xiàn)這一點(diǎn)。

一旦這些對(duì)象被挑選出來(lái),垃圾收集器就會(huì)通過(guò)確保它們的引用計(jì)數(shù)可以安全地降為零來(lái)刪除它們。

絕大多數(shù) Python 對(duì)象沒(méi)有引用周期,因此垃圾收集器不需要 24/7 運(yùn)行。相反,垃圾收集器使用一些啟發(fā)式方法來(lái)減少運(yùn)行頻率,并且每次都盡可能高效地運(yùn)行。

當(dāng) Python 解釋器啟動(dòng)時(shí),它會(huì)跟蹤已分配但未釋放的對(duì)象數(shù)量。絕大多數(shù) Python 對(duì)象的生命周期都很短,因此它們會(huì)迅速出現(xiàn)和消失。但隨著時(shí)間的推移,更多長(zhǎng)壽的物體會(huì)出現(xiàn)。一旦超過(guò)一定數(shù)量的此類(lèi)對(duì)象堆積起來(lái),垃圾收集器就會(huì)運(yùn)行。

每次垃圾收集器運(yùn)行時(shí),它都會(huì)收集所有在收集中幸存下來(lái)的對(duì)象,并將它們放在一個(gè)稱(chēng)為一代的組中。這些“第一代”對(duì)象在參考周期中被掃描的頻率較低。任何在垃圾收集器中幸存下來(lái)的第一代對(duì)象最終都會(huì)遷移到第二代,在那里它們被掃描得更少。

同樣,垃圾收集器不會(huì)跟蹤所有內(nèi)容。例如,像用戶創(chuàng)建的類(lèi)這樣的復(fù)雜對(duì)象總是被跟蹤。但是不會(huì)跟蹤僅包含簡(jiǎn)單對(duì)象(如整數(shù)和字符串)的字典,因?yàn)樵撎囟ㄗ值渲械娜魏螌?duì)象都不會(huì)包含對(duì)其他對(duì)象的引用。不能保存對(duì)其他元素(如整數(shù)和字符串)的引用的簡(jiǎn)單對(duì)象永遠(yuǎn)不會(huì)被跟蹤。

如何使用 gc 模塊

通常,垃圾收集器不需要調(diào)整即可運(yùn)行良好。Python 的開(kāi)發(fā)團(tuán)隊(duì)選擇了反映最常見(jiàn)現(xiàn)實(shí)世界場(chǎng)景的默認(rèn)值。但是如果你確實(shí)需要調(diào)整垃圾收集的工作方式,你可以使用Python 的 gc 模塊。該gc模塊為垃圾收集器的行為提供編程接口,并提供對(duì)正在跟蹤的對(duì)象的可見(jiàn)性。

gc當(dāng)你確定不需要垃圾收集器時(shí),你可以做的一件有用的事情是關(guān)閉它。例如,如果你有一個(gè)堆放大量對(duì)象的短運(yùn)行腳本,則不需要垃圾收集器。腳本結(jié)束時(shí),所有內(nèi)容都將被清除。為此,你可以使用命令禁用垃圾收集器gc.disable()。稍后,你可以使用 重新啟用它gc.enable()。

你還可以使用 手動(dòng)運(yùn)行收集周期gc.collect()。一個(gè)常見(jiàn)的應(yīng)用是管理程序的性能密集型部分,該部分會(huì)生成許多臨時(shí)對(duì)象。你可以在程序的該部分禁用垃圾收集,然后在最后手動(dòng)運(yùn)行收集并重新啟用收集。

另一個(gè)有用的垃圾收集優(yōu)化是gc.freeze(). 發(fā)出此命令時(shí),垃圾收集器當(dāng)前跟蹤的所有內(nèi)容都被“凍結(jié)”,或者被列為免于將來(lái)的收集掃描。這樣,未來(lái)的掃描可以跳過(guò)這些對(duì)象。如果你有一個(gè)程序在啟動(dòng)之前導(dǎo)入庫(kù)并設(shè)置大量?jī)?nèi)部狀態(tài),那么你可以gc.freeze()在所有工作完成后發(fā)出。這使垃圾收集器不必搜尋那些無(wú)論如何都不太可能被刪除的東西。(如果你想對(duì)凍結(jié)的對(duì)象再次執(zhí)行垃圾收集,請(qǐng)使用gc.unfreeze().)

使用 gc 調(diào)試?yán)占?/span>

你還可以使用它gc來(lái)調(diào)試?yán)占袨?。如果你有過(guò)多的對(duì)象堆積在內(nèi)存中并且沒(méi)有被垃圾收集,你可以使用gc's 檢查工具來(lái)找出可能持有對(duì)這些對(duì)象的引用的對(duì)象。

如果你想知道哪些對(duì)象持有對(duì)給定對(duì)象的引用,可以使用gc.get_referrers(obj)列出它們。你還可以使用gc.get_referents(obj)來(lái)查找給定對(duì)象引用的任何對(duì)象。

如果你不確定給定對(duì)象是否是垃圾收集的候選對(duì)象,gc.is_tracked(obj)請(qǐng)告訴你垃圾收集器是否跟蹤該對(duì)象。如前所述,請(qǐng)記住垃圾收集器不會(huì)跟蹤“原子”對(duì)象(例如整數(shù))或僅包含原子對(duì)象的元素。

如果你想親自查看正在收集哪些對(duì)象,可以使用 設(shè)置垃圾收集器的調(diào)試標(biāo)志gc.set_debug(gc.DEBUG_LEAK|gc.DEBUG_STATS)。這會(huì)將有關(guān)垃圾收集的信息寫(xiě)入stderr。它將所有作為垃圾收集的對(duì)象保留在只讀列表中。

避免 Python 內(nèi)存管理中的陷阱

如前所述,如果你在某處仍有對(duì)它們的引用,則對(duì)象可能會(huì)堆積在內(nèi)存中而不會(huì)被收集。這并不是 Python 垃圾收集本身的失敗。垃圾收集器無(wú)法判斷你是否不小心保留了對(duì)某物的引用。

讓我們以一些防止對(duì)象永遠(yuǎn)不會(huì)被收集的指針作為結(jié)尾。

注意對(duì)象范圍

如果你將對(duì)象 1 指定為對(duì)象 2 的屬性(例如類(lèi)),則對(duì)象 2 將需要超出范圍,然后對(duì)象 1 才會(huì):

obj1 = MyClass()
obj2.prop = obj1

更重要的是,如果這種情況發(fā)生在某種其他操作的副作用中,例如將對(duì)象 2 作為參數(shù)傳遞給對(duì)象 1 的構(gòu)造函數(shù),你可能不會(huì)意識(shí)到對(duì)象 1 持有一個(gè)引用:

obj1 = MyClass(obj2)

另一個(gè)例子:如果你將一個(gè)對(duì)象推入模塊級(jí)列表并忘記該列表,則該對(duì)象將一直保留,直到從列表中刪除,或者直到列表本身不再有任何引用。但是如果該列表是一個(gè)模塊級(jí)對(duì)象,它可能會(huì)一直存在,直到程序終止。

簡(jiǎn)而言之,請(qǐng)注意你的對(duì)象可能被另一個(gè)看起來(lái)并不總是很明顯的對(duì)象持有的方式。

使用 weakref避免引用循環(huán)

Python 的 weakref 模塊允許你創(chuàng)建對(duì)其他對(duì)象的弱引用。弱引用不會(huì)增加對(duì)象的引用計(jì)數(shù),因此只有弱引用的對(duì)象是垃圾回收的候選對(duì)象。

一個(gè)常見(jiàn)的用途weakref是對(duì)象緩存。你不希望僅僅因?yàn)樗哂芯彺鏃l目而保留引用的對(duì)象,因此你將 aweakref用于緩存條目。

手動(dòng)中斷參考循環(huán)

最后,如果你知道給定對(duì)象包含對(duì)另一個(gè)對(duì)象的引用,你總是可以手動(dòng)中斷對(duì)該對(duì)象的引用。例如,如果你有instance_of_class.ref = other_object,你可以設(shè)置instance_of_class.ref = None何時(shí)準(zhǔn)備刪除 instance_of_class。

通過(guò)了解 Python 內(nèi)存管理的工作原理,我們對(duì)其垃圾收集系統(tǒng)如何幫助優(yōu)化 Python 程序中的內(nèi)存,以及如何使用標(biāo)準(zhǔn)庫(kù)和其他地方提供的模塊來(lái)控制內(nèi)存使用和垃圾收集。

原文標(biāo)題:??Python garbage collection and the gc module??

責(zé)任編輯:黃顯東 來(lái)源: 51CTO
相關(guān)推薦

2020-05-13 08:10:32

HTTPS安全網(wǎng)站

2023-12-10 13:37:23

Python編程上下文管理

2019-11-12 14:40:43

CPU緩存內(nèi)存

2023-11-06 07:23:06

API開(kāi)發(fā)生態(tài)系統(tǒng)

2023-12-08 14:13:00

MemrayPython內(nèi)存

2021-11-30 07:51:29

共享內(nèi)存進(jìn)程

2009-12-17 11:37:39

Linux網(wǎng)卡

2021-02-07 09:02:28

內(nèi)存管理length

2018-11-20 09:37:19

Java內(nèi)存模型

2024-08-02 14:52:00

2019-10-31 08:36:59

線程內(nèi)存操作系統(tǒng)

2011-08-08 15:14:11

PPPOE

2020-10-21 09:28:25

JS變量的內(nèi)存分配

2012-09-27 10:24:22

監(jiān)控機(jī)房

2012-09-06 17:54:28

2022-07-26 00:00:22

HTAP系統(tǒng)數(shù)據(jù)庫(kù)

2014-04-17 16:42:03

DevOps

2011-09-01 10:42:14

Objective-CCocoa內(nèi)存管理

2025-01-03 08:09:15

2010-09-07 14:54:01

PPP幀中繼
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)