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.
Pruebe los gc.get_referrers(obj)
. La documentación del módulo gc
len(gc.get_referrers(my_obj))