31

Я создал некоторый код python, который создает объект в цикле, и на каждой итерации он перезаписывает этот объект новым одним и тем же типом. Это делается 10 000 раз, а Python занимает 7 МБ памяти каждую секунду, пока не будет использована моя 3-гигабайтная ОЗУ. Кто-нибудь знает, как удалить объекты из памяти?Сбор мусора Python

+0

Связанный: http://stackoverflow.com/questions/759906/sys-getrefcount-continuation/759970#759970 – codeape

ответ

16

Вы не указали достаточно информации - это зависит от особенностей создаваемого объекта и того, что вы делаете с ним в цикле. Если объект не создает циклические ссылки, он должен быть освобожден на следующей итерации. Например, код

for x in range(100000): 
    obj = " " * 10000000 

не приведет к постоянно увеличивающемуся распределению памяти.

+0

Я создаю круговые ссылки в моем объекте. Не удается ли его удалить вручную? – utdiscant

+8

Python будет автоматически собирать объекты с круглыми ссылками, * если * ни один из объектов в эталонном цикле не имеет методов __del__. Если это так, объекты мусора перемещаются в список gc.garbage, и вам придется вручную разбить эталонные циклы. Лучше попытаться избежать использования методов __del__ и эталонных циклов. – Miles

+5

Одним из способов избежать ссылочных циклов является использование слабых сторон: http://docs.python.org/library/weakref.html – Miles

12

Это старая ошибка, которая была исправлена ​​для некоторых типов в python 2.5. Случилось то, что python не был так хорош в сборе таких вещей, как пустые списки/словари/tupes/floats/ints. В python 2.5 это было исправлено ... в основном. Однако float и ints являются синглтонами для сравнений, поэтому, когда один из них создается, он остается вокруг до тех пор, пока интерпретатор жив. Я был укушен этим худшим, имея дело с большим количеством поплавков, так как у них неприятная привычка быть уникальной. Это было охарактеризовано как for python 2.4 и обновлено о нем: python 2.5

Лучший способ, которым я нашел это, - перейти на python 2.5 или новее, чтобы заботиться о проблемах с списками/словарями/кортежами. Для чисел единственным решением является не допускать попадания больших чисел чисел в питон. Я сделал это с моей собственной оболочкой для объекта C++, но у меня сложилось впечатление, что numpy.array даст похожие результаты.

В качестве пост-скрипта я понятия не имею, что случилось с этим в python 3, но я подозрительно, что числа все еще являются частью одноэлементного. Таким образом, утечка памяти на самом деле является признаком языка.

+1

Это не должно отвечать за проблему, как описано, однако; даже Python 2.4 должен повторно использовать освобожденную память (она просто не вернула ее в операционную систему). – Miles

+1

Не уверен, что мой эксперимент правильный, но временное создание миллионов поплавков определенно имело постоянное использование памяти. Помещение одинаковых поплавков в «список» увеличило использование памяти 100 МБ/с. Это было на 2,7 ... так что я думаю, по крайней мере, в 2.7 проблема не выходит? Я что-то упускаю? –

1

Вот одна вещь, которую вы можете сделать в REPL, чтобы заставить разыменования переменной:

>>> x = 5 
>>> x 
5 
>>> del x 
>>> x 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
NameError: name 'x' is not defined 
+1

В типичной программе проще и понятнее просто оставить свои переменные недоступными, чем явно удалять их. Конечно, если ваша целая программа - одна длинная функция, тогда ничего не выйдет за рамки до ее окончания. Это одна из причин того, что одна длинная функция не является рекомендуемым способом написания программ. – MatrixFrog

5

Если вы создаете циклические ссылки, ваши объекты не будут освобождаться немедленно, но придется подождать цикл GC для запуска.

Вы можете использовать модуль weakref, чтобы решить эту проблему, или явно указать объекты после использования.

3

я обнаружил, что в моем случае (с Python 2.5.1), с циклическими ссылками, связанных с классами, которые имеют __del__() методы, не только был сбор мусора не происходит своевременно, то __del__() методы моих объектов никогда не вызывался , даже когда скрипт вышел. Поэтому я использовал weakref, чтобы разбить круговые ссылки, и все было хорошо.

Kudos to Miles, который предоставил всю информацию в своих комментариях для меня, чтобы собрать это вместе.

+0

Если какой-либо объект цикла имеет метод '__del__', тогда цикл не является мусором, собираемым' gc'. См. Https://stackoverflow.com/a/15974956/1959808 –

19

Я думаю, что это циклическое (хотя вопрос не является явным об этой информации.)

Одним из способов решения этой проблемы является вручную вызвать сборку мусора. Когда вы вручную запускаете сборщик мусора, он будет также перемещать объекты, связанные с ссылками.

import gc 

for i in xrange(10000): 
    j = myObj() 
    processObj(j) 
    #assuming count reference is not zero but still 
    #object won't remain usable after the iteration 

    if !(i%100): 
     gc.collect() 

Здесь не запускайте сборщик мусора слишком часто, поскольку он имеет свои собственные накладные расходы, например. если вы запускаете сборщик мусора в каждом цикле, интерпретация будет очень медленной.