Форум сайта python.su
До этого писал сервисы практически без классов, а сейчас возникла необходимость очень интенсивно их использовать и у меня есть некоторые сомнения.
Проблема в том что эти сервисы работают по несколько лет без возможности перезагрузки или вмешательст, и меня беспокоят в первую очередь утечки памяти.
И наконец вопрос
class A:
pass
class B:
def __init__(self,param):
self.A=param
self.A.B=self
test=B(A())
Офлайн
Это простая связь которую хорошо отследить, но у меня в процессе работы образуется тьма классов с кучей подобных связей.
хм очень интересно а __del__ не выполняется не для A не для B Ж))
я думаю del удаляет его только из глобальноо пространства имен но он остается в классе a :\
есть ли способ удалить все разом :\
Отредактировано (Ноя. 16, 2008 12:03:33)
Офлайн
Всем спасибо, проблемму решил если кому интересно :)
Вобщем, нельзя делать мотод __del__ иначе фокус не получится
import gc
gc.enable()
import time
class A:
def __init__(self):
self.data=' '*1024*1024*30
class B:
def __init__(self,param):
self.A=param
self.A.B=self
test=B(A())
time.sleep(30)
del test
print gc.collect()
print gc.garbage
time.sleep(30)
Офлайн
Нет необходимости использовать gc непосредственно. Все неиспользуемые ресурсы и так будут освобождены, просто не известно точно когда. Так же стоит воздерживаться от использования __del__, не могу сказать точно в чем подоплека, но механизм освобождения ресурсов, в таком случае, работает иначе. Другими словами тебе придется подбирать за собой самому.
class A:
def __init__(self):
self.data = ' '*1024*1024*30
def __del__(self):
del self.data
class B:
def __init__(self,param):
self.A = param
self.A.B = self
def __del__(self):
del self.A.B
del self.A
Офлайн
gc действительно сам все неплохо собирает - нужно только дать ему время в случаях с кольцами.
Как я понимаю функционирование __del__. Если колец нет - все работает хорошо. Неплохим способом решения проблемы циклических связей является вставка weakref.
Если попалось кольцо с __del__ - питон этот случай тоже корректно отлавливает, но не может знать точный порядок вызова __del__ в объектах кольца, поэтому смущается и предпочитает “оставить все как есть” - может, программист сам разберется.
Офлайн
Опыты с __del__ показывают что ресурсы не освобождаются, gc я использую непосредственно потому что многие классы очень большие и ждать пока их gc выкинет нет смысла, а когда они не нужны я знаю точно.
Офлайн
Как я уже говорил, обычная причина для этого - кольца.
:
>>> class Parent(object):
... def __init__(self):
... self.children = []
... def add(self, ch):
... self.children.append(ch)
... ch.parent = self
...
>>> class Child(object):
... def __init__(self):
... self.parent = None
...
>>>
>>> p = Parent()
>>> p.add(Child())
>>> p
<__main__.Parent ...>
>>> p.children
[<__main__.Child ...>]
>>> class Child(object):
... def __init__(self):
... self._parent = None
... def _get_parent(self):
... return self._parent()
... def _set_parent(self, parent):
... self._parent = weakref.ref(parent)
... parent = property(_get_parent, _set_parent)
...
Офлайн
> __del__ нельзя вставить ни в Parent ни в Child - gc не справится с освобождением.
Он иногда, всё же необходим. В таком случае, как я показал, придётся освобождать ресурсы (сносить ссылки) ручками.
Т.е. Я не понял. __del__ в таком случае, что-ли, не будет вызван?
..bw
Офлайн
Объект может быть удален двумя способами: garbage collection и decref - когда счетчик ссылок становится равным 0.
Если нет циклических ссылок - работает первый способ. И тогда __del__ вызывается.
Если есть кольца - периодически запускается garbage collector, пытающийся найти “подвисшие” циклы (т.е. те, на которые отсутствуют ссылки снаружи) и удалить их. garbage collector __del__ не вызывает потому что не знает правильный порядок вызова деструкторов - и не удаляет объекты с __del__.
bw, когда ты “сносишь ссылки” вручную - то разрываешь циклическую связь, и все удаляется по decref.
Альтернатива, как я уже писал - недопускание колец на раннем этапе посредством применения weakref - тогда до gc дело не доходит и __del__ нормально отрабатывает.
Офлайн
Муть какая. Как-то до сих пор не предавал значения данной теме и связанным с ней проблемам. Я про циклические ссылки, __del__, в принципе, никогда не использую. Ну как я понимаю циклические ссылки всё же успешно разрешаются (удаляются объекты) в автоматическом режиме, просто такое разрешение может затянуться, если его не форсировать gc.collect()'ом?
> bw, когда ты “сносишь ссылки” вручную - то разрываешь циклическую связь, и все удаляется по decref.
Здесь я говорил о чистке таких ссылок в момент срабатывания __del__.
> garbage collector __del__ не вызывает потому что не знает правильный порядок вызова деструкторов - и не удаляет объекты с __del__
Считаю это не нормальным поведением.
Андрей Светлов, спасибо, за разъяснения.
Вывод такой - надо больше думать, что ты делаешь :-).
..bw
Офлайн