requests库中的内存泄漏
我注意到在使用requests库获取一个pdf文件时,内存使用量大幅增加。这个文件本身大约是4MB,但分配给python进程的实际内存却增加了超过150MB!
有没有人知道造成这种情况的可能原因(或者解决办法)?
这是测试案例:
import requests,gc
def dump_mem():
s = open("/proc/self/status").readlines()
for line in s:
if line.startswith("VmRSS"):
return line
下面是我在解释器中得到的输出。
>>> gc.collect()
0
>>> dump_mem()
'VmRSS:\t 13772 kB\n'
>>> gc.collect()
0
>>> r = requests.get('http://www.ipd.uni-karlsruhe.de/~ovid/Seminare/DWSS05/Ausarbeitungen/Seminar-DWSS05')
>>> gc.collect()
5
>>> dump_mem()
'VmRSS:\t 20620 kB\n'
>>> r.headers['content-length']
'4089190'
>>> dump_mem()
'VmRSS:\t 20628 kB\n'
>>> gc.collect()
0
>>> c = r.content
>>> dump_mem()
'VmRSS:\t 20628 kB\n'
>>> gc.collect()
0
>>> t = r.text
>>> gc.collect()
8
>>> dump_mem()
'VmRSS:\t 182368 kB\n'
显然,我不应该把pdf文件当作文本来解码。但是,这种情况的原因到底是什么呢?
1 个回答
7
当内容类型中没有包含charset
参数,并且响应不是text/
类型时,系统会使用一个字符检测库来判断编码方式。
使用response.text
时,你就触发了这个检测,加载了这个库,而它的模块里包含了一些比较大的数据表。
根据你安装的requests
的具体版本,你会发现sys.modules['requests.packages.chardet']
或sys.modules['requests.packages.charade']
现在已经存在了,还有大约36个子模块,这些在你使用r.text
之前是没有的。
在检测过程中,会创建一些对象,这些对象会对你的PDF文档使用各种统计技术,因为检测没有足够的把握找到特定的编码方式。为了能把这些数据放进内存,Python会请求操作系统分配更多的内存。一旦检测过程完成,这些内存会被释放,但操作系统不会立即回收这些内存。这是为了防止内存的频繁申请和释放,因为进程可能会在循环中频繁请求和释放内存。
需要注意的是,你还把r.text
的结果存储到了内存中,绑定到t
。这是一个Unicode文本对象,在Python 2中,它占用的内存是字节字符串对象的2到4倍。你下载的这个内容作为字节字符串大约是4MB,但如果你使用的是UCS-4的Python版本,那么解码后的Unicode值会额外增加16MB的内存仅仅是为了这个解码后的值。