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.
Во время моей недавней охоты за memleak в моем приложении я сузил его до модулей, а именно: неспособность мусора собирать незагруженный модуль. Используя любой метод, указанный ниже, чтобы выгрузить модуль, выдает тысячи объектов в памяти. Другими словами - я не могу выгрузить модуль в 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
... Argh! Мы вернемся к полностью импортированному 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