force collector python list object reference garbage-collection

collector - python free memory



En Python: ¿Cómo eliminar un objeto de una lista si solo se hace referencia en esa lista? (4)

Esta respuesta es la misma que la de Kevin, pero estaba trabajando en una implementación de ejemplo con referencias débiles y la estoy publicando aquí. El uso de referencias débiles resuelve el problema donde la lista de self.instance hace referencia a un objeto, por lo que nunca se eliminará.

Una de las cosas sobre la creación de una referencia débil para un objeto es que puede incluir una devolución de llamada cuando se elimina el objeto. Hay problemas, como que la devolución de llamada no se produce cuando el programa sale ... pero eso puede ser lo que quiera de todos modos.

import threading import weakref class A(object): instances = [] lock = threading.RLock() @classmethod def _cleanup_ref(cls, ref): print(''cleanup'') # debug with cls.lock: try: cls.instances.remove(ref) except ValueError: pass def __init__(self): with self.lock: self.instances.append(weakref.ref(self, self._cleanup_ref)) # test test = [A() for _ in range(3)] for i in range(3,-1,-1): assert len(A.instances) == i if test: test.pop() print("see if 3 are removed at exit") test = [A() for _ in range(3)]

Quiero hacer un seguimiento de los objetos de cierto tipo que están actualmente en uso. Por ejemplo: realizar un seguimiento de todas las instancias de una clase o todas las clases que han sido creadas por una metaclase.

Es fácil hacer un seguimiento de instancias como esta:

class A(): instances = [] def __init__(self): self.instances.append(self)

Pero si no se hace referencia a una instancia en cualquier lugar fuera de esa lista, ya no será necesaria y no quiero procesar esa instancia en un bucle que potencialmente requiera mucho tiempo.

Intenté eliminar objetos a los que solo se hace referencia en la lista mediante sys.getrefcount.

for i in A.instances: if sys.getrefcount(i) <=3: # in the list, in the loop and in getrefcount # collect and remove after the loop

El problema que tengo es que el recuento de referencias es muy oscuro. Abrir un nuevo shell y crear una clase ficticia sin contenido devuelve 5 para

sys.getrefcount(DummyClass)

Otra idea es copiar los objetos y luego eliminar la lista y verificar qué objetos se han programado para la recolección de basura y, en el último paso, eliminarlos. Algo como:

Copy = copy(A.instances) del A.instances A.instances = [i for i in Copy if not copy_of_i_is_in_GC(i)]

Los objetos no tienen que ser eliminados inmediatamente cuando el recuento de referencia va a 0. Simplemente no quiero desperdiciar demasiados recursos en objetos que ya no se usan.


Gracias a @Barmar por indicar el uso de weakref . Podemos combinarlo con el método __del__ para implementar una lista de instancias de autogestión de una clase. Por lo tanto, la class A en la publicación de OP se puede ampliar como:

from weakref import ref class A(): instances = [] def __init__(self): self.instances.append(ref(self)) @staticmethod def __del__(): if A: A.instances = [i for i in A.instances if not i() is None]

Pruebas

#python2.7 print dict((len(A.instances), A()) for i in range(5)).keys() # 0,1,2,3,4 print len(A.instances) # 0

El destructor __del__ se puede declarar como un método estático o como un método enlazado a objetos como def __del__(self): aunque no está documentado. Este último puede evitar que el objeto se destruya creando otra referencia a él. Aquí utilizo el estático porque no hay necesidad de otra referencia al objeto de morir. El código anterior se prueba en Python 2.7 y 3.3.

La weakref.ref llamada weakref.ref comporta de manera similar a __del__ excepto que está vinculada al objeto "weakref". Por lo tanto, si crea varias referencias débiles para el mismo objeto con la misma función de devolución de llamada, se llamará exactamente al mismo tiempo que la cantidad de referencias débiles.


La forma estándar de resolver este problema es a través de referencias débiles . La idea básica es mantener una lista de referencias débiles a objetos en lugar de los objetos en sí, y podar periódicamente las referencias débiles muertas de la lista.

Para los diccionarios y conjuntos, hay algunos tipos más abstractos como weakref.WeakKeyDictionary() que se pueden usar cuando se quieren colocar referencias débiles en lugares más complejos como las claves de un diccionario. Estos tipos no requieren poda manual.