TL/DR:descargar un módulo en Python
import gc, sys
print len(gc.get_objects()) # 4073 objects in memory
# Attempt to unload the module
import httplib
del sys.modules["httplib"]
httplib = None
gc.collect()
print len(gc.get_objects()) # 6745 objects in memory
ACTUALIZACIÓN me he puesto en contacto desarrolladores de Python sobre este problema y de hecho es not going to be possible to unload a module por completo "en los próximos cinco años". (ver el enlace)
Acepte que Python de hecho no admite módulos de descarga para problemas técnicos graves, fundamentales, insuperables, en 2.x.
Durante mi reciente búsqueda de un memleak en mi aplicación, me he reducido a los módulos, a saber, mi incapacidad para recoger la basura un módulo de carga. Usando cualquier método listado a continuación para descargar un módulo deja miles de objetos en la memoria. En otras palabras - No puedo descargar un módulo en Python ...
El resto de la pregunta es intento de recoger la basura un módulo de alguna manera. try
Vamos:
import gc
import sys
sm = sys.modules.copy() # httplib, which we'll try to unload isn't yet
# in sys.modules, so, this isn't the source of problem
print len(gc.get_objects()) # 4074 objects in memory
Salvemos una copia de sys.modules
a intentar restaurarla más tarde. Entonces, esta es una referencia de 4074 objetos. Idealmente, deberíamos volver a esto de alguna manera.
Vamos a importar un módulo:
import httplib
print len(gc.get_objects()) # 7063 objects in memory
estamos hasta 7K objetos que no son basura. Probemos eliminando httplib
de sys.modules
.
sys.modules.pop('httplib')
gc.collect()
print len(gc.get_objects()) # 7063 objects in memory
Bueno, eso no funcionó. Hmm, ¿pero no hay una referencia en __main__
? Oh, sí:
del httplib
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
Hooray, baja 300 objetos. Aún así, no hay cigarros, eso es mucho más de 4000 objetos originales. Tratemos de restaurar sys.modules
desde la copia.
sys.modules = sm
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
Hmmm, así que no tenía sentido, ningún cambio .. Tal vez si eliminamos a variables globales ...
globals().clear()
import gC# we need this since gc was in globals() too
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
locales?
locals().clear()
import gC# we need this since gc was in globals() too
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
Lo que el .. ¿y si nos imported
un módulo dentro de exec
?
local_dict = {}
exec 'import httplib' in local_dict
del local_dict
gc.collect()
print len(gc.get_objects()) # back to 7063 objects in memory
Ahora, eso no es justo, lo que importó en __main__
, ¿por qué? Nunca debería haber salido del local_dict
... Argh! Volvemos a totalmente importado httplib
. ¿Tal vez si lo reemplazamos con un objeto ficticio?
from types import ModuleType
import sys
print len(gc.get_objects()) # 7064 objects in memory
Bloody ..... !!
sys.modules['httplib'] = ModuleType('httplib')
print len(gc.get_objects()) # 7066 objects in memory
Die modules, die !!
import httplib
for attr in dir(httplib):
setattr(httplib, attr, None)
gc.collect()
print len(gc.get_objects()) # 6749 objects in memory
bien, después de todos los intentos, lo mejor es 2,675 (casi el + 50%) desde el punto de partida ... eso es sólo de un módulo ... Eso ni siquiera tiene nada grande por dentro ...
Bien, ahora en serio, ¿dónde está mi error? ¿Cómo descargo un módulo y borro todos sus contenidos? ¿O los módulos de Python son una pérdida de memoria gigante?
fuente completo en el más simple de copiar formulario: http://gist.github.com/450606
Sí, carga un número razonablemente ilimitado de módulos: es un servidor de aplicaciones web que acepta nuevas revisiones de su propio código fuente y lo vuelve a cargar (esta es una tarea web bastante estándar). La fuga ES del hecho de que el código anterior aún está en la memoria, incluso si se reemplaza, incluso si no se puede acceder ... –
Python admite módulos de descarga. Son basura recolectada, como cualquier otro objeto en Python. –
@Slava: Es posible que desee echar un vistazo al código fuente a 'mod_python', que tiene su propio importador que está diseñado para manejar los módulos de recarga sin producir pérdidas de memoria. Puede haber algún código allí que puedas usar. –