2014-01-11 59 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的,也不符合龙卷风和Pypy泄漏!只有在使用Twisted和Pypy时,代码才会泄漏,并且仅在使用POST请求时才会泄漏。

要查看泄漏情况,您必须发送数十万个请求。

请注意,设置PYPY_GC_MAX时,该进程最终会崩溃。

发生了什么事?

+1

那你观察到让你觉得有内存泄漏?你确定PyPy上的程序的大小不只是大于CPython的大小? –

+0

很难100%确定,但你可以继续并仔细检查我的陈述。测试在很长一段时间内完成。例如,用Cyclone回答几十万个GET请求,使得进程使用的内存达到63兆字节,而使用与POST请求完全相同的测试会导致该进程使用400兆字节并继续占用越来越多的内存。 我们正在运行生产服务器,每秒处理数千个请求,并使用Cyclone代码运行数天,而使用Python 2.7则无内存问题。这个问题只发生在PyPy上。 –

+1

在Debian unstable中使用软件包时,我得到的行为是,PyPy使用120MB启动,在前1000个请求后启动到125MB,并在接下来的5000个请求中保持该内存使用级别。我没有让它遇到成千上万的请求,因为内存使用似乎在只有一千个请求后达到稳定的水平。也许现在Debian不稳定版本的PyPy或Cyclone(或其他依赖项)软件包比您测试的版本更新或更旧,并且问题已得到解决或引入? –

回答