Уведомления

Группа в Telegram: @pythonsu

#1 Ноя. 16, 2008 11:43:42

evgenyl
От:
Зарегистрирован: 2008-07-22
Сообщения: 148
Репутация: +  0  -
Профиль   Отправить e-mail  

Классы их переменные и память

До этого писал сервисы практически без классов, а сейчас возникла необходимость очень интенсивно их использовать и у меня есть некоторые сомнения.
Проблема в том что эти сервисы работают по несколько лет без возможности перезагрузки или вмешательст, и меня беспокоят в первую очередь утечки памяти.
И наконец вопрос

class A:
pass
class B:
def __init__(self,param):
self.A=param
self.A.B=self

test=B(A())
примерно такой код
меня интересует если я делаю del test удалится ли объект класса A ?
вообще если я делаю del <какойто класс>
применяет ли он del ко всем своим атрибутам ?
вообще кто занимался такой прблемой может что нить сказать ?
переопределить __del__ у A и проверить это я счас сделаю, но вообще интересен сам вопрос.



Офлайн

#2 Ноя. 16, 2008 11:59:36

evgenyl
От:
Зарегистрирован: 2008-07-22
Сообщения: 148
Репутация: +  0  -
Профиль   Отправить e-mail  

Классы их переменные и память

Это простая связь которую хорошо отследить, но у меня в процессе работы образуется тьма классов с кучей подобных связей.
хм очень интересно а __del__ не выполняется не для A не для B Ж))
я думаю del удаляет его только из глобальноо пространства имен но он остается в классе a :\
есть ли способ удалить все разом :\



Отредактировано (Ноя. 16, 2008 12:03:33)

Офлайн

#3 Ноя. 16, 2008 12:39:56

evgenyl
От:
Зарегистрирован: 2008-07-22
Сообщения: 148
Репутация: +  0  -
Профиль   Отправить e-mail  

Классы их переменные и память

Всем спасибо, проблемму решил если кому интересно :)
Вобщем, нельзя делать мотод __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)
можно запустить сборщик мусора, он удалит все недоступные классы которые не имеют метода __del__
все что не смог удалить(те что с методом __del__), будут доступны в переменной gc.garbage

если следить за памятью процесса она при старте 49 метров, через 30 секунд 19, т.е. то что нужно :)



Офлайн

#4 Ноя. 16, 2008 19:08:01

bw
От:
Зарегистрирован: 2007-09-26
Сообщения: 938
Репутация: +  20  -
Профиль   Адрес электронной почты  

Классы их переменные и память

Нет необходимости использовать 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
..bw



Офлайн

#5 Ноя. 16, 2008 23:53:41

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

Классы их переменные и память

gc действительно сам все неплохо собирает - нужно только дать ему время в случаях с кольцами.
Как я понимаю функционирование __del__. Если колец нет - все работает хорошо. Неплохим способом решения проблемы циклических связей является вставка weakref.
Если попалось кольцо с __del__ - питон этот случай тоже корректно отлавливает, но не может знать точный порядок вызова __del__ в объектах кольца, поэтому смущается и предпочитает “оставить все как есть” - может, программист сам разберется.



Офлайн

#6 Ноя. 17, 2008 10:11:05

evgenyl
От:
Зарегистрирован: 2008-07-22
Сообщения: 148
Репутация: +  0  -
Профиль   Отправить e-mail  

Классы их переменные и память

Опыты с __del__ показывают что ресурсы не освобождаются, gc я использую непосредственно потому что многие классы очень большие и ждать пока их gc выкинет нет смысла, а когда они не нужны я знаю точно.



Офлайн

#7 Ноя. 17, 2008 19:32:27

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

Классы их переменные и память

Как я уже говорил, обычная причина для этого - кольца.

:
>>> 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 ...>]
У нас получается кольцо: parent смотрит на child, а тот в свою очередь держит сильную ссылку на parent.
Объекты для удаления требуют пробежки gc (явной или отложенной-автоматической).
__del__ нельзя вставить ни в Parent ни в Child - gc не справится с освобождением.
Меняем код:
>>> 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)
...
Теперь обратная ссылка получилась слабой (можно использовать еще и weakref.proxy, но мне привычней явное разыменование). Кольца нет, объекты удаляются по decref не попадая в garbage collector, методы __del__ будут вызываться, gc.collect не требуется - в общем, все счастливы.



Офлайн

#8 Ноя. 18, 2008 09:07:03

bw
От:
Зарегистрирован: 2007-09-26
Сообщения: 938
Репутация: +  20  -
Профиль   Адрес электронной почты  

Классы их переменные и память

> __del__ нельзя вставить ни в Parent ни в Child - gc не справится с освобождением.
Он иногда, всё же необходим. В таком случае, как я показал, придётся освобождать ресурсы (сносить ссылки) ручками.
Т.е. Я не понял. __del__ в таком случае, что-ли, не будет вызван?

..bw



Офлайн

#9 Ноя. 18, 2008 17:54:47

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

Классы их переменные и память

Объект может быть удален двумя способами: garbage collection и decref - когда счетчик ссылок становится равным 0.
Если нет циклических ссылок - работает первый способ. И тогда __del__ вызывается.
Если есть кольца - периодически запускается garbage collector, пытающийся найти “подвисшие” циклы (т.е. те, на которые отсутствуют ссылки снаружи) и удалить их. garbage collector __del__ не вызывает потому что не знает правильный порядок вызова деструкторов - и не удаляет объекты с __del__.
bw, когда ты “сносишь ссылки” вручную - то разрываешь циклическую связь, и все удаляется по decref.
Альтернатива, как я уже писал - недопускание колец на раннем этапе посредством применения weakref - тогда до gc дело не доходит и __del__ нормально отрабатывает.



Офлайн

#10 Ноя. 18, 2008 19:19:39

bw
От:
Зарегистрирован: 2007-09-26
Сообщения: 938
Репутация: +  20  -
Профиль   Адрес электронной почты  

Классы их переменные и память

Муть какая. Как-то до сих пор не предавал значения данной теме и связанным с ней проблемам. Я про циклические ссылки, __del__, в принципе, никогда не использую. Ну как я понимаю циклические ссылки всё же успешно разрешаются (удаляются объекты) в автоматическом режиме, просто такое разрешение может затянуться, если его не форсировать gc.collect()'ом?

> bw, когда ты “сносишь ссылки” вручную - то разрываешь циклическую связь, и все удаляется по decref.
Здесь я говорил о чистке таких ссылок в момент срабатывания __del__.

> garbage collector __del__ не вызывает потому что не знает правильный порядок вызова деструкторов - и не удаляет объекты с __del__
Считаю это не нормальным поведением.

Андрей Светлов, спасибо, за разъяснения.
Вывод такой - надо больше думать, что ты делаешь :-).

..bw



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version