Форум сайта python.su
Целых 17 “зажатых” объектов. Должно быть 0. gc.garbage пустой, если перед этим не вызывал gc.set_debug(gc.DEBUG_LEAK)
Офлайн
Точно, теперь я в gc.garbage вижу как раз вот эти data, которые приходят в datagramReceived. Но я так понял, если эта цифра 17 не увеличивается, то и память не должна съедаться?
Офлайн
не совсем. Эти семнадцать объектов - “застрявшие”. Garbage collector не может их освободить (хотя и должен бы). Что “под ними” и кого они еще “держат” - не всегда видно. Но факт, что в “чистой” программе gc.collect() всегда возвращает 0.
Вывод - у тебя есть кольца (циклические ссылки).
Офлайн
Что интересно, вариант с deferred ест память в несколько раз медленнее..
Хотя нет, ошибся. Очень неравномерно растет, буду проверять.
Отредактировано (Май 22, 2008 20:49:39)
Офлайн
Ищи места, где нужно вставлять слабые ссылки (модуль weakref в помощь).
Еще можешь выложить свой пример с подробным описанием, как его завести (как я понимаю, слушаешь что-то вроде RTP и переправляешь пакеты через TCP). С указанием программ - источника медиа данных и конечного приемника. И указаниями, как их быстро поставить-настроить-запустить. (Примечание - у меня Винда, и серверного линукса нынче под рукой нет). Если все будет - посмотрю в чем дело, когда буду свободен.
Сейчас на работе дел много и мастер-класс на exception послезавтра…
P.S. Burus (burus.org) на последнем exception говорил, что одно их приложение на twisted тоже ело память как не в себя. После внимательного осмотра и небольших корректировок прочно сидит в положеных 30 MB. Мой опыт полностью это подтверждает.
Отредактировано (Май 23, 2008 01:18:02)
Офлайн
Кажется решил проблему. В этом мне помогла ссылка http://www.smira.ru/2008/02/09/python-memory-leak-resolved/ где такая же причина утечки. Клиент не успевает забирать данные и они копятся в каком-то буфере. Сам буфер я не нашел, поэтому пришлось писать напрямую в сокет:
def datagramReceived(self, data, address): # получаем пакет и посылаем его по всем затребовавшим for out in outputs: out.transport.socket.send(self.data) #out.write(data)
def writeSomeData(self, data): """Connection.writeSomeData(data) -> #of bytes written | CONNECTION_LOST This writes as much data as possible to the socket and returns either the number of bytes read (which is positive) or a connection error code (which is negative) """ try: # Limit length of buffer to try to send, because some OSes are too # stupid to do so themselves (ahem windows) return self.socket.send(buffer(data, 0, self.SEND_LIMIT)) except socket.error, se: if se.args[0] == EINTR: return self.writeSomeData(data) elif se.args[0] in (EWOULDBLOCK, ENOBUFS): return 0 else: return main.CONNECTION_LOST
Офлайн