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时,该进程最终会崩溃。
发生了什么事?
那你观察到让你觉得有内存泄漏?你确定PyPy上的程序的大小不只是大于CPython的大小? –
很难100%确定,但你可以继续并仔细检查我的陈述。测试在很长一段时间内完成。例如,用Cyclone回答几十万个GET请求,使得进程使用的内存达到63兆字节,而使用与POST请求完全相同的测试会导致该进程使用400兆字节并继续占用越来越多的内存。 我们正在运行生产服务器,每秒处理数千个请求,并使用Cyclone代码运行数天,而使用Python 2.7则无内存问题。这个问题只发生在PyPy上。 –
在Debian unstable中使用软件包时,我得到的行为是,PyPy使用120MB启动,在前1000个请求后启动到125MB,并在接下来的5000个请求中保持该内存使用级别。我没有让它遇到成千上万的请求,因为内存使用似乎在只有一千个请求后达到稳定的水平。也许现在Debian不稳定版本的PyPy或Cyclone(或其他依赖项)软件包比您测试的版本更新或更旧,并且问题已得到解决或引入? –