Heim  >  Artikel  >  Backend-Entwicklung  >  Detaillierte Erläuterung des Garbage-Collection-Mechanismus von Python

Detaillierte Erläuterung des Garbage-Collection-Mechanismus von Python

高洛峰
高洛峰Original
2017-03-24 17:34:451364Durchsuche

1. Garbage-Collection-Mechanismus
Die Garbage-Collection in Python basiert hauptsächlich auf Referenzzählung, ergänzt durch Generationen-Collection. Der Nachteil der Referenzzählung ist das Problem der Zirkelverweise.
Wenn in Python die Anzahl der Verweise auf ein Objekt 0 ist, beansprucht die virtuelle Python-Maschine den Speicher dieses Objekts zurück.

#encoding=utf-8
__author__ = 'kevinlu1010@qq.com'
 
class ClassA():
  def __init__(self):
    print 'object born,id:%s'%str(hex(id(self)))
  def __del__(self):
    print 'object del,id:%s'%str(hex(id(self)))
 
def f1():
  while True:
    c1=ClassA()
    del c1


Das Ausführen von f1() gibt solche Ergebnisse in einer Schleife aus und der vom Prozess belegte Speicher ändert sich grundsätzlich nicht

object born,id:0x237cf58
object del,id:0x237cf58


c1=ClassA () erstellt ein Objekt und platziert es im Speicher 0x237cf58. Zu diesem Zeitpunkt ist der Referenzzähler dieses Speichers 1.
Nach del c1 zeigt die Variable c1 nicht mehr auf 0x237cf58 Speicher, daher wird der Referenzzähler dieses Speichers um eins reduziert. Er ist gleich 0, sodass das Objekt zerstört und der Speicher freigegeben wird.
Eine Situation, die dazu führt, dass der Referenzzähler +1 beträgt
Das Objekt wird erstellt, zum Beispiel a=23
Das Objekt wird referenziert, zum Beispiel b=a
Das Objekt wird als Parameter an übergeben eine Funktion, wie zum Beispiel func( a) Das
-Objekt wird in einem Container als Element gespeichert, zum Beispiel list1=[a,a]
, wodurch der Referenzzähler auf -1
Der Alias ​​des Objekt wird explizit zerstört, zum Beispiel del a
Der Alias ​​des Objekts wird dem neuen Objekt zugewiesen, z. B. a=24
Ein Objekt verlässt seinen Gültigkeitsbereich, z. B. wenn die f-Funktion die Ausführung abschließt, das lokale Variable in der Funktion func (globale Variablen nicht)
Der Container, in dem sich das Objekt befindet, wird zerstört oder das Objekt wird aus dem Container gelöscht
Demo

def func(c,d):
  print 'in func function', sys.getrefcount(c) - 1
 
 
print 'init', sys.getrefcount(11) - 1
a = 11
print 'after a=11', sys.getrefcount(11) - 1
b = a
print 'after b=1', sys.getrefcount(11) - 1
func(11)
print 'after func(a)', sys.getrefcount(11) - 1
list1 = [a, 12, 14]
print 'after list1=[a,12,14]', sys.getrefcount(11) - 1
a=12
print 'after a=12', sys.getrefcount(11) - 1
del a
print 'after del a', sys.getrefcount(11) - 1
del b
print 'after del b', sys.getrefcount(11) - 1
# list1.pop(0)
# print 'after pop list1',sys.getrefcount(11)-1
del list1
print 'after del list1', sys.getrefcount(11) - 1


Ausgabe:

init 24
after a=11 25
after b=1 26
in func function 28
after func(a) 26
after list1=[a,12,14] 27
after a=12 26
after del a 26
after del b 25
after del list1 24


Frage: Warum erhöht der Aufruf der Funktion den Referenzzähler um 2
Überprüfen Sie den Referenzzähler eines Objekts
sys.getrefcount(a) kann den Referenzzähler von überprüfen ein Objekt, aber es ist 1 größer als die normale Anzahl, da beim Aufruf der Funktion a übergeben wird, wodurch sich die Referenzanzahl von a erhöht
2 Zirkelverweise führen zu Speicherverlusten

def f2():
  while True:
    c1=ClassA()
    c2=ClassA()
    c1.t=c2
    c2.t=c1
    del c1
    del c2


Wenn f2() ausgeführt wird, erhöht sich der vom Prozess belegte Speicher weiter.

object born,id:0x237cf30
object born,id:0x237cf58


Nach dem Erstellen von c1 und c2 gibt es Verweise auf diese beiden Speicher: 0x237cf30 (der Speicher entsprechend c1, aufgezeichnet als Speicher 1), 0x237cf58 (der Speicher entsprechend c2, aufgezeichnet als Speicher 2) Die Zählungen sind alle 1. Nach der Ausführung von c1.t=c2 und c2.t=c1 wird der Referenzzähler dieser beiden Speicherteile 2.
Nach del c1 der Referenzzähler des Objekts im Speicher 1 wird zu 1. Da es nicht 0 ist, wird das Objekt in Speicher 1 nicht zerstört, sodass die Anzahl der Verweise auf das Objekt in Speicher 2 immer noch 2 beträgt. Nach del c2 ist die Anzahl der Verweise auf die gleiche Weise auf Das Objekt in Speicher 1 und das Objekt in Speicher 2 ist 1.
Obwohl beide Objekte aufgrund von Zirkelverweisen zerstört werden können, werden sie vom Garbage Collector nicht recycelt, was zu einem Speicherverlust führt.
3. Garbage Collection

deff3():
  # print gc.collect()
  c1=ClassA()
  c2=ClassA()
  c1.t=c2
  c2.t=c1
  del c1
  del c2
  print gc.garbage
  print gc.collect() #显式执行垃圾回收
  print gc.garbage
  time.sleep(10)
if __name__ == '__main__':
  gc.set_debug(gc.DEBUG_LEAK) #设置gc模块的日志
  f3()


Ausgabe:
Python

gc: uncollectable <ClassA instance at 0230E918>
gc: uncollectable <ClassA instance at 0230E940>
gc: uncollectable <dict 0230B810>
gc: uncollectable <dict 02301ED0>
object born,id:0x230e918
object born,id:0x230e940


4
Nach der Garbage Collection Die Objekte werden in der gc.garbage-Liste abgelegt
gc.collect() gibt die Anzahl der nicht erreichbaren Objekte zurück, 4 entspricht zwei Objekten und ihrem entsprechenden Diktat
Es gibt drei Situationen, die die Garbage Collection auslösen:
1. Rufen Sie gc.collect() auf,
2. Wenn der Zähler des GC-Moduls den Schwellenwert erreicht.
3. Wenn das Programm beendet wird
4. Analyse der allgemeinen Funktionen des GC-Moduls

Garbage Collector interface


Das GC-Modul bietet eine Schnittstelle, die Entwickler festlegen können Garbage-Collection-Optionen. Wie oben erwähnt, ist einer der Mängel bei der Verwendung der Referenzzählmethode zur Speicherverwaltung der Zirkelverweis, und eine der Hauptfunktionen des GC-Moduls besteht darin, das Problem des Zirkelverweises zu lösen.
Häufig verwendete Funktionen:
gc.set_debug(flags)
Legen Sie das Debug-Protokoll von gc fest, im Allgemeinen auf gc.DEBUG_LEAK eingestellt
gc.collect([generation])
Explizite Speicherbereinigung, Sie können Parameter eingeben, 0 bedeutet, dass nur die Objekte der ersten Generation überprüft werden, 1 bedeutet, dass die Objekte der ersten und zweiten Generation überprüft werden, 2 bedeutet, dass die Objekte der ersten, zweiten und dritten Generation überprüft werden. Wenn keine Parameter übergeben werden , wird eine vollständige Sammlung ausgeführt, was der Übergabe von 2 entspricht.
Gibt die Anzahl der nicht erreichbaren Objekte zurück
gc.set_threshold(threshold0[, Schwellenwert1[, Schwellenwert2])
Legen Sie die Häufigkeit der automatischen Speicherbereinigung fest.
gc.get_count()
Ruft den aktuellen automatischen Garbage-Collection-Zähler ab und gibt eine Liste der Länge 3 zurück
Der automatische Garbage-Collection-Mechanismus des GC-Moduls
Das GC-Modul muss importiert werden und is_enable() =True startet die automatische Speicherbereinigung.
Die Hauptfunktion dieses Mechanismus besteht darin, unerreichbare Müllobjekte zu entdecken und damit umzugehen.
Garbage Collection = Garbage Check + Garbage Collection
In Python wird die Generations-Collection-Methode verwendet. Teilen Sie das Objekt zunächst in drei Generationen ein. Wenn das geänderte Objekt eine Müllprüfung der ersten Generation übersteht, wird es ebenfalls in die zweite Generation eingeordnet Garbage-Check der Generation: Wenn das Objekt den Garbage-Check übersteht, wird es in die dritte Generation verschoben.
Im gc-Modul gibt es einen Zähler mit einer Länge von 3, der über gc.get_count() abgerufen werden kann.
Zum Beispiel (488,3,0), wobei sich 488 auf die Anzahl des von Python zugewiesenen Speichers minus der Anzahl des freigegebenen Speichers seit der Müllprüfung der letzten Generation bezieht. Beachten Sie, dass es sich um eine Speicherzuweisung handelt, nicht um eine Erhöhung der Referenz zählen. Zum Beispiel:

print gc.get_count() # (590, 8, 0)
a = ClassA()
print gc.get_count() # (591, 8, 0)
del a
print gc.get_count() # (590, 8, 0)


3是指距离上一次二代垃圾检查,一代垃圾检查的次数,同理,0是指距离上一次三代垃圾检查,二代垃圾检查的次数。
gc模快有一个自动垃圾回收的阀值,即通过gc.get_threshold函数获取到的长度为3的元组,例如(700,10,10)
每一次计数器的增加,gc模块就会检查增加后的计数是否达到阀值的数目,如果是,就会执行对应的代数的垃圾检查,然后重置计数器
例如,假设阀值是(700,10,10):
当计数器从(699,3,0)增加到(700,3,0),gc模块就会执行gc.collect(0),即检查一代对象的垃圾,并重置计数器为(0,4,0)
当计数器从(699,9,0)增加到(700,9,0),gc模块就会执行gc.collect(1),即检查一、二代对象的垃圾,并重置计数器为(0,0,1)
当计数器从(699,9,9)增加到(700,9,9),gc模块就会执行gc.collect(2),即检查一、二、三代对象的垃圾,并重置计数器为(0,0,0)
其他
如果循环引用中,两个对象都定义了__del__方法,gc模块不会销毁这些不可达对象,因为gc模块不知道应该先调用哪个对象的__del__方法,所以为了安全起见,gc模块会把对象放到gc.garbage中,但是不会销毁对象。
五.应用
 项目中避免循环引用
 引入gc模块,启动gc模块的自动清理循环引用的对象机制
 由于分代收集,所以把需要长期使用的变量集中管理,并尽快移到二代以后,减少GC检查时的消耗
 gc模块唯一处理不了的是循环引用的类都有__del__方法,所以项目中要避免定义__del__方法,如果一定要使用该方法,同时导致了循环引用,需要代码显式调用gc.garbage里面的对象的__del__来打破僵局

Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung des Garbage-Collection-Mechanismus von Python. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn