Heim > Artikel > Backend-Entwicklung > Verstehen Sie, wie die Speicherverwaltung in Python funktioniert?
Python bietet Entwicklern viele Annehmlichkeiten, einer der größten ist die nahezu sorgenfreie Speicherverwaltung. Entwickler müssen in Python nicht mehr manuell Speicher für Objekte und Datenstrukturen zuweisen, verfolgen und freigeben. Die Laufzeit übernimmt die gesamte Arbeit für Sie, sodass Sie sich auf die Lösung tatsächlicher Probleme konzentrieren können, anstatt sich mit Details auf Maschinenebene auseinanderzusetzen.
Dennoch ist es auch für unerfahrene Python-Benutzer hilfreich zu verstehen, wie die Speicherbereinigung und Speicherverwaltung von Python funktioniert. Wenn Sie diese Mechanismen verstehen, können Sie Leistungsprobleme vermeiden, die bei komplexeren Projekten auftreten können. Sie können auch die integrierten Tools von Python verwenden, um das Speicherverwaltungsverhalten Ihres Programms zu überwachen.
Jedes Python-Objekt hat einen Referenzzähler, auch Referenzzähler genannt. refcount ist eine Zählung der Gesamtzahl anderer Objekte, die Verweise auf ein bestimmtes Objekt enthalten. Wenn Sie Verweise auf das Objekt hinzufügen oder entfernen, erhöht oder verringert sich die Zahl. Wenn der Referenzzähler eines Objekts Null erreicht, wird die Zuordnung des Objekts aufgehoben und sein Speicher freigegeben.
Was ist eine Referenz? Ermöglicht den Zugriff auf beliebige Inhalte eines Objekts über den Namen oder über einen Accessor in einem anderen Objekt.
Hier ist ein einfaches Beispiel:
x = "Hello there"
Wenn wir diesen Befehl an Python erteilen, passieren unter der Haube zwei Dinge:
Wenn wir y = x sagen, dann erhöht sich der Referenzzähler wieder auf 2.
Immer wenn xandy den Gültigkeitsbereich verlässt oder aus seinem Namespace entfernt wird, wird der Referenzzähler der Zeichenfolge für jeden Namen um 1 reduziert. Sobald sowohl x als auch y außerhalb des Bereichs liegen oder gelöscht werden, wird der Referenzzähler der Zeichenfolge zu 0 und wird gelöscht.
Angenommen, wir erstellen wie folgt eine Liste mit Zeichenfolgen:
x = ["Hello there", 2, False]
Die Zeichenfolge bleibt im Speicher, bis die Liste selbst gelöscht wird oder die Zeichenfolge enthält, aus der das Element entfernt wird die Liste. Jeder dieser Vorgänge führt dazu, dass das einzige Element verschwindet, das einen Verweis auf die Zeichenfolge enthält.
Betrachten Sie nun dieses Beispiel:
x = "Hello there" y = [x]
Wenn wir das erste Element y aus entfernen oder die Liste y vollständig entfernen, befindet sich die Zeichenfolge immer noch im Speicher. Dies liegt daran, dass der Name x einen Verweis darauf enthält.
In den meisten Fällen funktioniert die Referenzzählung einwandfrei. Aber manchmal kommt es vor, dass zwei Objekte jeweils eine Referenz zueinander enthalten. Dies wird als Referenzzeitraum bezeichnet. In diesem Fall erreicht der Referenzzähler des Objekts niemals Null und es wird niemals aus dem Speicher gelöscht.
Dies ist ein erfundenes Beispiel:
x = SomeClass() y = SomeOtherClass() x.item = y y.item = x
Da x und y Verweise aufeinander enthalten, werden sie nie aus dem System gelöscht – auch ohne etwas anderes. Zitieren Sie einen von ihnen.
Es ist eigentlich durchaus üblich, dass Pythons eigene Laufzeit Referenzzyklen für Objekte generiert. Ein Beispiel ist eine Ausnahme mit einem Traceback-Objekt, das einen Verweis auf die Ausnahme selbst enthält.
In früheren Versionen von Python war dies ein Problem. Objekte mit Referenzzyklen können sich im Laufe der Zeit ansammeln, was bei lang laufenden Anwendungen ein großes Problem darstellt. Aber Python hat inzwischen Zykluserkennungs- und Garbage-Collection-Systeme zur Verwaltung von Referenzzyklen eingeführt.
Pythons Garbage Collector erkennt Objekte mit Referenzzyklen. Dies geschieht durch die Verfolgung von Objekten, die „Container“ sind (z. B. Listen, Wörterbücher, benutzerdefinierte Klasseninstanzen) und durch die Bestimmung, auf welche von ihnen nirgendwo anders zugegriffen werden kann.
Sobald diese Objekte ausgewählt wurden, löscht der Garbage Collector sie, indem er sicherstellt, dass ihre Referenzanzahl sicher auf Null sinken kann.
Die überwiegende Mehrheit der Python-Objekte hat keine Referenzzyklen, sodass der Garbage Collector nicht rund um die Uhr laufen muss. Stattdessen verwendet der Garbage Collector einige Heuristiken, um die Ausführung seltener und jedes Mal so effizient wie möglich zu gestalten.
Wenn der Python-Interpreter startet, verfolgt er die Anzahl der Objekte, die zugewiesen, aber nicht freigegeben wurden. Die überwiegende Mehrheit der Python-Objekte ist kurzlebig, sodass sie schnell erscheinen und verschwinden. Aber mit der Zeit werden immer mehr langlebige Objekte auftauchen. Sobald sich mehr als eine bestimmte Anzahl solcher Objekte ansammelt, wird der Garbage Collector ausgeführt.
Jedes Mal, wenn der Garbage Collector ausgeführt wird, sammelt er alle Objekte, die die Sammlung überlebt haben, und ordnet sie einer Gruppe zu, die als Generation bezeichnet wird. Diese Objekte der „ersten Generation“ werden im Referenzzyklus seltener gescannt. Alle Objekte der ersten Generation, die den Garbage Collector überleben, werden schließlich in die zweite Generation migriert, wo sie weniger häufig gescannt werden.
同样,垃圾收集器不会跟踪所有内容。例如,像用户创建的类这样的复杂对象总是被跟踪。但是不会跟踪仅包含简单对象(如整数和字符串)的字典,因为该特定字典中的任何对象都不会包含对其他对象的引用。不能保存对其他元素(如整数和字符串)的引用的简单对象永远不会被跟踪。
通常,垃圾收集器不需要调整即可运行良好。Python 的开发团队选择了反映最常见现实世界场景的默认值。但是如果你确实需要调整垃圾收集的工作方式,你可以使用Python 的 gc 模块。该gc模块为垃圾收集器的行为提供编程接口,并提供对正在跟踪的对象的可见性。
gc当你确定不需要垃圾收集器时,你可以做的一件有用的事情是关闭它。例如,如果你有一个堆放大量对象的短运行脚本,则不需要垃圾收集器。脚本结束时,所有内容都将被清除。为此,你可以使用命令禁用垃圾收集器gc.disable()。稍后,你可以使用 重新启用它gc.enable()。
你还可以使用 手动运行收集周期gc.collect()。一个常见的应用是管理程序的性能密集型部分,该部分会生成许多临时对象。你可以在程序的该部分禁用垃圾收集,然后在最后手动运行收集并重新启用收集。
另一个有用的垃圾收集优化是gc.freeze(). 发出此命令时,垃圾收集器当前跟踪的所有内容都被“冻结”,或者被列为免于将来的收集扫描。这样,未来的扫描可以跳过这些对象。如果你有一个程序在启动之前导入库并设置大量内部状态,那么你可以gc.freeze()在所有工作完成后发出。这使垃圾收集器不必搜寻那些无论如何都不太可能被删除的东西。(如果你想对冻结的对象再次执行垃圾收集,请使用gc.unfreeze().)
你还可以使用它gc来调试垃圾收集行为。如果你有过多的对象堆积在内存中并且没有被垃圾收集,你可以使用gc's 检查工具来找出可能持有对这些对象的引用的对象。
如果你想知道哪些对象持有对给定对象的引用,可以使用gc.get_referrers(obj)列出它们。你还可以使用gc.get_referents(obj)来查找给定对象引用的任何对象。
如果你不确定给定对象是否是垃圾收集的候选对象,gc.is_tracked(obj)请告诉你垃圾收集器是否跟踪该对象。如前所述,请记住垃圾收集器不会跟踪“原子”对象(例如整数)或仅包含原子对象的元素。
如果你想亲自查看正在收集哪些对象,可以使用 设置垃圾收集器的调试标志gc.set_debug(gc.DEBUG_LEAK|gc.DEBUG_STATS)。这会将有关垃圾收集的信息写入stderr。它将所有作为垃圾收集的对象保留在只读列表中。
如前所述,如果你在某处仍有对它们的引用,则对象可能会堆积在内存中而不会被收集。这并不是 Python 垃圾收集本身的失败。垃圾收集器无法判断你是否不小心保留了对某物的引用。
让我们以一些防止对象永远不会被收集的指针作为结尾。
如果你将对象 1 指定为对象 2 的属性(例如类),则对象 2 将需要超出范围,然后对象 1 才会:
obj1 = MyClass() obj2.prop = obj1
更重要的是,如果这种情况发生在某种其他操作的副作用中,例如将对象 2 作为参数传递给对象 1 的构造函数,你可能不会意识到对象 1 持有一个引用:
obj1 = MyClass(obj2)
另一个例子:如果你将一个对象推入模块级列表并忘记该列表,则该对象将一直保留,直到从列表中删除,或者直到列表本身不再有任何引用。但是如果该列表是一个模块级对象,它可能会一直存在,直到程序终止。
简而言之,请注意你的对象可能被另一个看起来并不总是很明显的对象持有的方式。
Python 的 weakref 模块允许你创建对其他对象的弱引用。弱引用不会增加对象的引用计数,因此只有弱引用的对象是垃圾回收的候选对象。
一个常见的用途weakref是对象缓存。你不希望仅仅因为它具有缓存条目而保留引用的对象,因此你将 aweakref用于缓存条目。
Wenn Sie schließlich wissen, dass ein bestimmtes Objekt einen Verweis auf ein anderes Objekt enthält, können Sie einen Verweis auf dieses Objekt jederzeit manuell unterbrechen. Wenn Sie beispielsweise „instance_of_class.ref = other_object“ haben, können Sie „instance_of_class.ref = None“ festlegen, wenn Sie zum Löschen von „instance_of_class“ bereit sind.
Anhand des Verständnisses der Python-Speicherverwaltung werfen wir einen Blick darauf, wie das Garbage-Collection-System dabei hilft, den Speicher in Python-Programmen zu optimieren, und wie Sie die Speichernutzung und die Garbage-Collection mithilfe von Modulen steuern können, die von der Standardbibliothek und anderswo bereitgestellt werden.
Originaltitel:Python Garbage Collection und das GC-Modul
Das obige ist der detaillierte Inhalt vonVerstehen Sie, wie die Speicherverwaltung in Python funktioniert?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!