2014-01-11 1 views
4

После многих исследований выяснилось, что после обслуживания сотен тысяч HTTP-запросов POST происходит утечка памяти. Странная часть заключается в том, что утечка памяти возникает только при использовании PyPy.Использование Twisted + Cyclone + PyPy для обработки запросов POST вызывает утечку памяти?

Вот пример код:

from twisted.internet import reactor 
import tornado.ioloop 

do_tornado = False 
port = 8888 

if do_tornado: 
    from tornado.web import RequestHandler, Application 
else: 
    from cyclone.web import RequestHandler, Application 

class MainHandler(RequestHandler): 
    def get(self): 
     self.write("Hello, world") 

    def post(self): 
     self.write("Hello, world") 

if __name__ == "__main__": 
    routes = [(r"/", MainHandler)] 
    application = Application(routes) 

    print port 
    if do_tornado: 
     application.listen(port) 
     tornado.ioloop.IOLoop.instance().start() 
    else: 
     reactor.listenTCP(port, application) 
     reactor.run() 

Вот тестовый код, я использую для создания запросов:

from twisted.internet import reactor, defer 
from twisted.internet.task import LoopingCall 

from twisted.web.client import Agent, HTTPConnectionPool 
from twisted.web.iweb import IBodyProducer 

from zope.interface import implements 

pool = HTTPConnectionPool(reactor, persistent=True) 
pool.retryAutomatically = False 
pool.maxPersistentPerHost = 10 
agent = Agent(reactor, pool=pool) 

bid_url = 'http://localhost:8888' 

class StringProducer(object): 
    implements(IBodyProducer) 

    def __init__(self, body): 
     self.body = body 
     self.length = len(body) 

    def startProducing(self, consumer): 
     consumer.write(self.body) 
     return defer.succeed(None) 

    def pauseProducing(self): 
     pass 

    def stopProducing(self): 
     pass 


def callback(a): 
    pass 

def error_callback(error): 
    pass 

def loop(): 
    d = agent.request('POST', bid_url, None, StringProducer("Hello, world")) 
    #d = agent.request('GET', bid_url) 
    d.addCallback(callback).addErrback(error_callback) 


def main(): 
    exchange = LoopingCall(loop) 
    exchange.start(0.02) 

    #log.startLogging(sys.stdout) 
    reactor.run() 

main() 

Обратите внимание, что этот код не попадал с CPython, ни с Tornado и PyPy! Код протекает только при использовании Twisted и Pypy вместе, и ТОЛЬКО при использовании запроса POST.

Чтобы увидеть утечку, вы должны отправить сотни тысяч запросов.

Обратите внимание, что при установке PYPY_GC_MAX процесс в конечном итоге сбой.

Что происходит?

+1

Что вы заметили, что заставляет вас думать, что есть утечка памяти? Вы уверены, что размер программы на PyPy не больше размера на CPython? –

+0

Трудно быть на 100% уверенным, но вы можете продолжить и дважды проверить мои заявления. Тесты проводились в течение очень длительного периода времени. Например, отвечая на сотни тысяч запросов GET с помощью Cyclone, выгружает память, используемую процессом, в 63 мегабайта, тогда как использование одного и того же теста с запросом POST заставило процесс использовать 400 мегабайт и продолжать брать все больше и больше памяти. Мы запускаем серверы производства, которые обрабатывают тысячи запросов в секунду с помощью кода Cyclone, который работает в течение нескольких дней без проблем с памятью, используя Python 2.7. Эта проблема возникает только с PyPy. –

+1

Использование пакетов в Debian нестабильно, поведение, которое я получаю, заключается в том, что PyPy запускается с использованием 120 МБ, переходит на 125 МБ после первых 1000 запросов и остается на этом уровне использования памяти для следующих 5000 запросов. Я не позволял ему работать сотнями тысяч запросов, так как использование памяти, казалось, достигло стабильного уровня после всего тысячи запросов. Возможно, версия пакетов PyPy или Cyclone (или другой зависимости) в Debian нестабильна сейчас более новая или более старая, чем версии, с которыми вы тестировали, и проблема была исправлена ​​или введена? –

ответ