TL / DR:
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
ОБНОВЛЕНИЕ Я связался с разработчиками Python по этой проблеме, и действительно не удастся выгрузить модуль полностью "в ближайшие пять лет".(см. ссылку)
Пожалуйста, примите, что Python действительно не поддерживает разгрузку модулей для серьезных, фундаментальных, непреодолимых технических проблем в 2.x.
Во время моей недавней охоты на утечку памяти в моем приложении я сузил ее до модулей, а именно из-за неспособности собрать мусор выгруженного модуля.Использование любого метода, указанного ниже, для выгрузки модуля оставляет в памяти тысячи объектов.Другими словами - я не могу выгрузить модуль в Python ...
Остальная часть вопроса - попытка каким-то образом собрать мусор модуля.
Давайте попробуем:
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
Давайте сохраним копию sys.modules
, чтобы попытаться восстановить ее позже.Итак, это базовые 4074 объекта.В идеале мы должны как-то вернуться к этому.
Давайте импортируем модуль:
import httplib
print len(gc.get_objects()) # 7063 objects in memory
Мы до 7K объектов без мусора.Давайте попробуем удалить httplib
из sys.modules
.
sys.modules.pop('httplib')
gc.collect()
print len(gc.get_objects()) # 7063 objects in memory
Ну, это не сработало.Хм, а разве нет ссылки в __main__
?Ах да:
del httplib
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
Ура, вниз 300 объектов.Тем не менее, нет сигары, это более 4000 оригинальных предметов.Давайте попробуем восстановить sys.modules
из копии.
sys.modules = sm
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
Хммм, ну, это было бессмысленно, без изменений .. Может быть, если мы уничтожим глобалы ...
globals().clear()
import gc # we need this since gc was in globals() too
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
местных жителей?
locals().clear()
import gc # we need this since gc was in globals() too
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
Что за ... что если мы imported
модуль внутри 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
Теперь, это не честно, он импортировал его в __main__
, почему?Он никогда не должен был покидать local_dict
... Аааа!Мы возвращаемся к полностью импортированным httplib
.Может быть, если мы заменим его фиктивным объектом?
from types import ModuleType
import sys
print len(gc.get_objects()) # 7064 objects in memory
Кровавый ..... !!
sys.modules['httplib'] = ModuleType('httplib')
print len(gc.get_objects()) # 7066 objects in memory
Умрите модули, умрите !!
import httplib
for attr in dir(httplib):
setattr(httplib, attr, None)
gc.collect()
print len(gc.get_objects()) # 6749 objects in memory
Хорошо, после всех попыток, лучшее - это +2675 (почти + 50%) от начальной точки ... Это только от одного модуля ... У него даже нет ничего большого ...
Хорошо, теперь серьезно, где моя ошибка?Как выгрузить модуль и уничтожить все его содержимое?Или модули Python - это гигантская утечка памяти?
Полный исходный код в более простой для копирования форме: http://gist.github.com/450606