Уведомления

Группа в Telegram: @pythonsu

#1 Май 22, 2008 10:49:31

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

Ретрансляция udp multicast в http на Twisted

Целых 17 “зажатых” объектов. Должно быть 0. gc.garbage пустой, если перед этим не вызывал gc.set_debug(gc.DEBUG_LEAK)



Офлайн

#2 Май 22, 2008 13:39:04

init
От:
Зарегистрирован: 2008-05-15
Сообщения: 12
Репутация: +  0  -
Профиль   Отправить e-mail  

Ретрансляция udp multicast в http на Twisted

Точно, теперь я в gc.garbage вижу как раз вот эти data, которые приходят в datagramReceived. Но я так понял, если эта цифра 17 не увеличивается, то и память не должна съедаться?



Офлайн

#3 Май 22, 2008 15:33:28

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

Ретрансляция udp multicast в http на Twisted

не совсем. Эти семнадцать объектов - “застрявшие”. Garbage collector не может их освободить (хотя и должен бы). Что “под ними” и кого они еще “держат” - не всегда видно. Но факт, что в “чистой” программе gc.collect() всегда возвращает 0.
Вывод - у тебя есть кольца (циклические ссылки).



Офлайн

#4 Май 22, 2008 20:43:10

init
От:
Зарегистрирован: 2008-05-15
Сообщения: 12
Репутация: +  0  -
Профиль   Отправить e-mail  

Ретрансляция udp multicast в http на Twisted

Что интересно, вариант с deferred ест память в несколько раз медленнее..

Хотя нет, ошибся. Очень неравномерно растет, буду проверять.



Отредактировано (Май 22, 2008 20:49:39)

Офлайн

#5 Май 23, 2008 00:43:23

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

Ретрансляция udp multicast в http на Twisted

Ищи места, где нужно вставлять слабые ссылки (модуль weakref в помощь).
Еще можешь выложить свой пример с подробным описанием, как его завести (как я понимаю, слушаешь что-то вроде RTP и переправляешь пакеты через TCP). С указанием программ - источника медиа данных и конечного приемника. И указаниями, как их быстро поставить-настроить-запустить. (Примечание - у меня Винда, и серверного линукса нынче под рукой нет). Если все будет - посмотрю в чем дело, когда буду свободен.
Сейчас на работе дел много и мастер-класс на exception послезавтра…
P.S. Burus (burus.org) на последнем exception говорил, что одно их приложение на twisted тоже ело память как не в себя. После внимательного осмотра и небольших корректировок прочно сидит в положеных 30 MB. Мой опыт полностью это подтверждает.



Отредактировано (Май 23, 2008 01:18:02)

Офлайн

#6 Май 30, 2008 17:19:13

init
От:
Зарегистрирован: 2008-05-15
Сообщения: 12
Репутация: +  0  -
Профиль   Отправить e-mail  

Ретрансляция udp multicast в http на Twisted

Кажется решил проблему. В этом мне помогла ссылка 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)

В таком виде память не съедается. Причина непосредственно утечки, как мне кажется, кроется в методе writeSomeData класса Connection из internet.tcp. Код выглядит так:

    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

Если я все правильно понял, то если в данный момент в буфере сокета уже есть неотправленные данные, то socket.send генерирует исключение, в одном из которых эта функция рекурсивно вызывается снова. То есть если появится клиент с низкой скоростью, то быстро наплодится очень много вызовов этой функции. Не знаю, прав я или нет, но других причин найти не смог.



Офлайн

Board footer

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

Powered by DjangoBB

Lo-Fi Version