python - HTTPS 请求 CurlAsyncHTTPClient 内存泄漏

标签 python python-2.7 curl tornado pycurl

我的处理程序文件

# -*- coding:utf-8 -*-
import sys
from tornado import gen, web, httpclient

url = "https://mdetail.tmall.com/templates/pages/desc?id=527485572414"

class SearchHandler(web.RequestHandler):
    @gen.coroutine
    def get(self):
        async_client = httpclient.AsyncHTTPClient()
        print sys.getrefcount(async_client) # The first time less than 10, then always bigger than 200
        req = httpclient.HTTPRequest(url, "GET", headers=headers)
        req_lists = [async_client.fetch(req) for _ in range(200)]
        r = yield req_lists
        print sys.getrefcount(async_client) # always bigger than 200
        # The longer req_lists, the more memory will be consumed, and never decrease

配置文件

tornado.httpclient.AsyncHTTPClient.configure(client, max_clients=1000)

如果我的客户端是“tornado.curl_httpclient.CurlAsyncHTTPClient”,那么当我在broswer中访问我的处理程序时,htop显示内存增加了大约6GB,只要进程运行时,内存占用永不减少

如果我将范围(200)设置为范围(500)或更高,内存使用量会更高

如果我的线路是,内存几乎不会增加

我发现仅获取https://就会出现内存问题

如何解决 CurlAsyncHTTPClient 的内存问题?

环境:

Ubuntu 16.10 x64
python2.7.12
Tornado 4.5.1

最佳答案

您看到的引用计数是预期的,因为 max_clients=1000 ,Tornado会缓存并重用1000 pycurl.Curl instances ,其中每个都可能 hold a reference到客户端的_curl_header_callback。您可以通过 objgraph.show_backrefs 看到它.

您真的需要 max_clients=1000 — 即最多并行 1000 个请求吗? (我希望它们不会像您的示例一样全部连接到同一服务器!)

无论如何,Curl 实例似乎占用了大量内存。

在我的系统(Ubuntu 16.04)上,当使用链接到系统范围的 libcurl3-gnutls 7.47.0 的 PycURL 时,我可以重现该问题:

$ /usr/bin/time -v python getter.py 
6
207
^C
[...]
    Maximum resident set size (kbytes): 4853544

当我将 PycURL 与新构建的 libcurl 7.54.1(仍具有 GnuTLS 后端)链接时,我得到了更好的结果:

$ LD_LIBRARY_PATH=$PWD/curl-prefix/lib /usr/bin/time -v python getter.py 
6
207
^C
[...]
    Maximum resident set size (kbytes): 1016084

如果我将 libcurl 与 OpenSSL 后端一起使用,结果会更好:

    Maximum resident set size (kbytes): 275572

还有其他有关 GnuTLS 内存问题的报告:curl issue #1086 .

因此,如果您确实需要大型 max_clients,请尝试使用使用 OpenSSL 后端构建的较新的 libcurl。

关于python - HTTPS 请求 CurlAsyncHTTPClient 内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45498537/

相关文章:

python - 控制台彩色文本更改字符串长度

python-2.7 - "class_names"in export_graphviz 意外关键字错误

发出 HTTP 请求时,Python 子进程静默崩溃

Python ctypes dll 加载错误 487

linux - 在 Linux 中使用 cURL 进行 HTTP POST 和 GET

python - 将新元组加入 Python 中的第一个元组列表

python TypeError "unsupported operand type(s) for +: ' int' 和 'str' “为什么我会得到这个?

python - 更改 lxml 中 etree.tostring 的默认缩进

java - 在 Tomcat 上 curl 部署版本化 war

php - 使用 Curl get_info 获取 HTML 文件中图像的内容类型