Maison  >  Article  >  développement back-end  >  Explication détaillée du mécanisme de récupération de place de Python

Explication détaillée du mécanisme de récupération de place de Python

高洛峰
高洛峰original
2017-03-24 17:34:451308parcourir

1. Mécanisme de collecte des déchets
Le nettoyage des déchets en Python est principalement basé sur le comptage de références, complété par une collecte générationnelle. L'inconvénient du comptage de références est le problème des références circulaires.
En Python, si le nombre de références à un objet est 0, la machine virtuelle Python récupérera la mémoire de cet objet.

#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


L'exécution de f1() produira ces résultats dans une boucle, et la mémoire occupée par le processus ne changera fondamentalement pas

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


c1=ClassA () va créer un objet et le placer dans la mémoire 0x237cf58. La variable c1 pointe vers cette mémoire. A ce moment, le nombre de références de cette mémoire est 1
Après del c1, la variable c1 ne pointe plus vers le 0x237cf58. mémoire, donc le compteur de références de cette mémoire est réduit de un. Il est égal à 0, donc l'objet est détruit et la mémoire est libérée.
Une situation qui amène le décompte de références à +1
L'objet est créé, par exemple a=23
L'objet est référencé, par exemple b=a
L'objet est passé en paramètre à une fonction, telle que func( a) L'objet
est stocké dans un conteneur en tant qu'élément, par exemple list1=[a,a]
, ce qui fait que le nombre de références est
L'alias du. l'objet est explicitement détruit, par exemple del a
L'alias de l'objet est attribué au nouvel objet, tel que a=24
Un objet quitte sa portée, par exemple, lorsque la fonction f termine son exécution, le local variable dans la fonction func (les variables globales ne le seront pas)
Le conteneur où se trouve l'objet est détruit, ou l'objet est supprimé du conteneur
démo

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


Sortie :

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


Question : Pourquoi l'appel de la fonction augmente-t-il le nombre de références de 2
Vérifier le nombre de références d'un objet
sys.getrefcount(a) peut vérifier le nombre de références de un objet, mais il est 1 plus grand que le nombre normal, car a est transmis lors de l'appel de la fonction, ce qui augmentera le nombre de références de a 1
2 Les références circulaires entraînent des fuites de mémoire<.>

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

Lorsque f2() est exécuté, la mémoire occupée par le processus continuera d'augmenter.

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

Après avoir créé c1 et c2, il y a des références à ces deux mémoires : 0x237cf30 (la mémoire correspondant à c1, enregistrée comme mémoire 1), 0x237cf58 (la mémoire correspondant à c2, enregistrée comme mémoire 2) Les comptes sont tous 1. Après avoir exécuté c1.t=c2 et c2.t=c1, le compte de référence de ces deux morceaux de mémoire devient 2.
Après del c1, le compte de référence de l'objet en mémoire 1 devient 1. Parce qu'il n'est pas 0, donc l'objet en mémoire 1 ne sera pas détruit, donc le nombre de références à l'objet en mémoire 2 est toujours 2. Après del c2, de la même manière, le nombre de références à l'objet en mémoire 1 et l'objet en mémoire 2 valent 1.
Bien que leurs deux objets puissent être détruits, en raison de références circulaires, le ramasse-miettes ne les recyclera pas, provoquant ainsi une fuite de mémoire.

3. Collecte des ordures

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()

Sortie :
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
Après la collecte des ordures Les objets seront placés dans la liste gc.garbage
gc.collect() renverra le nombre d'objets inaccessibles, 4 est égal à deux objets et leur dict correspondant
Il y a trois situations qui déclencheront le garbage collection :
1. Appelez gc.collect(),
2. Lorsque le compteur du module gc atteint le seuil.
3. Lorsque le programme se termine

4. Analyse des fonctions communes du module gc

Garbage Collector interface

Le module gc fournit une interface que les développeurs peuvent définir. options de collecte des déchets. Comme mentionné ci-dessus, l'un des défauts de l'utilisation de la méthode de comptage de références pour gérer la mémoire est la référence circulaire, et l'une des fonctions principales du module gc est de résoudre le problème de la référence circulaire.
Fonctions couramment utilisées :
gc.set_debug(flags)
Définissez le journal de débogage de gc, généralement défini sur gc.DEBUG_LEAK
gc.collect([génération])
Goumasse explicite, Vous pouvez saisir des paramètres, 0 signifie vérifier uniquement les objets de la première génération, 1 signifie vérifier les objets des première et deuxième générations, 2 signifie vérifier les objets des première, deuxième et troisième générations si aucun paramètre n'est transmis. , une collection complète sera exécutée, ce qui équivaut à passer 2 .
Renvoie le nombre d'objets inaccessibles
gc.set_threshold(threshold0[, seuil1[, seuil2])
Définissez la fréquence du garbage collection automatique.
gc.get_count()
Obtenir le compteur de garbage collection automatique actuel et renvoyer une liste de longueur 3
Le mécanisme de garbage collection automatique du module gc
Le module gc doit être importé et is_enable() =True lancera le garbage collection automatique.
La fonction principale de ce mécanisme est de découvrir et de traiter les objets indésirables inaccessibles.
Garbage collection = garbage check + garbage collection
En Python, la méthode de collecte générationnelle est utilisée. Divisez l'objet en trois générations. Initialement, lorsque l'objet est créé, il est placé dans la première génération. Si l'objet modifié survit à un garbage check de la première génération, il sera placé dans la deuxième génération. génération garbage check, Si l'objet survit au garbage check, il sera placé dans la troisième génération.
Il y aura un compteur dans le module gc d'une longueur de 3, qui peut être obtenu via gc.get_count().
Par exemple (488,3,0), où 488 fait référence au nombre de mémoire allouée par Python moins le nombre de mémoire libérée depuis le garbage check de dernière génération. Notez qu'il s'agit d'une allocation de mémoire, pas d'une augmentation de la référence. compter. Par exemple :

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__来打破僵局

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn