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
попытаться восстановить его позже. Так, это - базовая линия 4 074 объекта. Мы должны идеально возвратиться к этому так или иначе.
Давайте импортируем модуль:
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 объектов. Однако, никакая сигара, это - путь больше чем 4 000 исходных объектов. Давайте попытаемся восстановить sys.modules
из копии.
sys.modules = sm
gc.collect()
print len(gc.get_objects()) # 6746 objects in memory
Хм, хорошо это было бессмысленно, никакое изменение.. Возможно, если мы вытираем globals...
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
Python не поддерживает выгрузку модулей.
Однако, если ваша программа не загружает неограниченное количество модулей с течением времени, это не является источником утечки памяти. Модули обычно загружаются один раз при запуске и все. Скорее всего, утечка памяти происходит в другом месте.
В маловероятном случае, если ваша программа действительно загружает неограниченное количество модулей с течением времени, вам, вероятно, следует перепроектировать свою программу. ;-)
. Я не уверен насчет Python, но на других языках вызов эквивалента gc.collect ()
не не освобождает неиспользуемую память - он освобождает эту память, только если / когда память действительно нужна .
В противном случае для Python имеет смысл временно оставить модули в памяти на случай, если их потребуется снова загрузить.
(Вам следует попытаться написать более сжатые вопросы; я прочитал только начало и просмотрел все остальное.) Вначале я вижу простую проблему:
sm = sys.modules.copy()
Вы сделали копию sys.modules, так что теперь ваш copy имеет ссылку на модуль - поэтому, конечно, он не будет собран. Вы можете увидеть, что к нему относится, с помощью gc.get_referrers.
Это отлично работает:
# module1.py
class test(object):
def __del__(self):
print "unloaded module1"
a = test()
print "loaded module1"
.
# testing.py
def run():
print "importing module1"
import module1
print "finished importing module1"
def main():
run()
import sys
del sys.modules["module1"]
print "finished"
if __name__ == '__main__':
main()
module1 выгружается, как только мы удаляем его из sys.modules, потому что не осталось ссылок на модуль. (Выполнение module1 = None
после импорта тоже будет работать - я просто поместил импорт в другую функцию для ясности. Все, что вам нужно сделать, это отбросить ссылки на него.)
Теперь это На практике это немного сложно сделать из-за двух проблем:
В общем случае есть несколько сложных проблем: определение того, какие модули зависят от модуля, который вы выгружаете; знание того, можно ли их выгружать (сильно зависит от вашего варианта использования); обработка потоков при изучении всего этого (взгляните на imp.acquire_lock) и так далее.
Я мог бы придумать случай, когда это могло бы быть полезно, но в большинстве случаев я бы рекомендовал просто перезапустить приложение, если его код изменится. Скорее всего, у вас просто начнется головная боль.