进程内存变得巨大

我正在使用Tornado CurlAsyncHTTPClient。 当我为每个请求实例化相应的httpclient时,我的进程内存对于阻塞和非阻塞请求都在持续增长。 如果我只有一个httpclient实例(tornado.httpclient.HTTPClient / tornado.httpclient.AsyncHTTPClient)并且重用它们,则不会发生此内存使用增长。

另外如果我使用SimpleAsyncHTTPClient而不是CurlAsyncHTTPClient,这种内存增长不会发生,而不管我如何实例化。

这里是一个示例代码,它重现了这一点,

import tornado.httpclient
import json
import functools

instantiate_once = False
tornado.httpclient.AsyncHTTPClient.configure('tornado.curl_httpclient.CurlAsyncHTTPClient')

hc, io_loop, async_hc = None, None, None
if instantiate_once:
    hc = tornado.httpclient.HTTPClient()
    io_loop = tornado.ioloop.IOLoop()
    async_hc = tornado.httpclient.AsyncHTTPClient(io_loop=io_loop)

def fire_sync_request():
    global count
    if instantiate_once:
        global hc
    if not instantiate_once:
        hc = tornado.httpclient.HTTPClient()
    url = '<Please try with a url>'
    try:
        resp = hc.fetch(url)
    except (Exception,tornado.httpclient.HTTPError) as e:
        print str(e)
    if not instantiate_once:
        hc.close()

def fire_async_requests():
    #generic response callback fn
    def response_callback(response):
        response_callback_info['response_count'] += 1
        if response_callback_info['response_count'] >= request_count:
            io_loop.stop()
    if instantiate_once:
        global io_loop, async_hc
    if not instantiate_once:
        io_loop = tornado.ioloop.IOLoop()
    requests = ['<Please add ur url to try>']*5
    response_callback_info = {'response_count': 0}
    request_count = len(requests)
    global count
    count +=request_count
    hcs=[]
    for url in requests:
        kwargs ={}
        kwargs['method'] = 'GET'
       if not instantiate_once:
            async_hc = tornado.httpclient.AsyncHTTPClient(io_loop=io_loop)
        async_hc.fetch(url, callback=functools.partial(response_callback), **kwargs)
        if not instantiate_once:
        hcs.append(async_hc)

    io_loop.start()
    for hc in hcs:
        hc.close()
    if not instantiate_once:
        io_loop.close()

if __name__ == '__main__':
    import sys
    if sys.argv[1] == 'sync':
        while True:
            output = fire_sync_request()
    elif sys.argv[1] == 'async':
        while True:
            output = fire_async_requests()

这里设置instantiate_once变量为True,并执行python check.py sync或python check.py async。 进程内存不断增加

使用instantiate_once = False,这不会发生。

此外,如果我使用SimpleAsyncHTTPClient而不是CurlAsyncHTTPClient,则内存增长不会发生。

我有python 2.7 / tornado 2.3.2 / pycurl(libcurl / 7.26.0 GnuTLS / 2.12.20 zlib / 1.2.7 libidn / 1.25 libssh2 / 1.4.2 librtmp / 2.3)

我可以用最新的龙卷风3.2重现同样的问题

请帮我理解这种行为并找出将龙卷风作为http库使用的正确方法。


HTTPClient和AsyncHTTPClient被设计为可以重用,所以它总是更有效,而不是一直重新创建它们。 实际上,AsyncHTTPClient会尝试神奇地检测是否存在相同IOLoop上的现有AsyncHTTPClient,并使用该AsyncHTTPClient而不是创建新的。

但即使最好重用一个http客户端对象,也不应该因为你在这里(只要你关闭它们)而泄漏来创建它们中的许多对象。 这看起来像pycurl中的一个错误:https://github.com/pycurl/pycurl/issues/182


使用pycurl 7.19.5和这个hack来避免内存泄漏:

您的龙卷风主文件:

tornado.httpclient.AsyncHTTPClient.configure("curl_httpclient_leaks_patched.CurlAsyncHTTPClientEx")

curl_httpclient_leaks_patched.py

from tornado import curl_httpclient

class CurlAsyncHTTPClientEx(curl_httpclient.CurlAsyncHTTPClient):

    def close(self):
        super(CurlAsyncHTTPClientEx, self).close()
        del self._multi
链接地址: http://www.djcxy.com/p/66925.html

上一篇: Process Memory grows huge

下一篇: Memory leak when using strings < 128KB in Python?