python进程内存撑大了下不去,只能手动重启释放内存,这么坑爹的事情你遇到过吗?哪家内存分配器强?结果一目了然。
线上进程目前都是使用原生的Python内存分配器(pymalloc),在正常的情况下表现还算稳定,但如果来了一波类似于武神坛或者天下第一的比武大会,为手机瞬间带来了10倍于平时的流量,一阵狂虐之后,Python进程占用的内存被撑大就下不去了。关于Python的内存不释放问题,可以参考一下这两篇文章:python内存不释放原理,Python memory management and TCMalloc。
为了解决内存泄漏的问题,我专门使用了三种编译方式去编译Python2.7解释器
以下分别使用pymalloc、without-pymalloc、tcmalloc测试1千万个object的list内存释放情况(注:默认使用Python2.7)。
- 测试环境
CPU | 4 QEMU Virtual CPU version 2.1.0 |
---|---|
内存 | 15G |
操作系统内核 | Linux onlinegame-229-88 3.2.0-4-amd64 #1 SMP Debian 3.2.60-1+deb7u1 x86_64 GNU/Linux |
- 测试代码
#!/usr/bin/env python
# coding: utf-8
import os
import gc
import time
class Test:
def __init__(self):
self.name = "haha"
def run():
L = []
begin = time.time()
for i in xrange():
L.append(Test())
end = time.time()
print 'cost:%s' %(round(end-begin,))
input_str = raw_input('\nrun: ')
if __name__=="__main__":
print "pid:%s" %os.getpid()
input_str = raw_input('\nstart')
run()
input_str = raw_input('\nready to collect')
gc.collect()
input_str = raw_input('\ncollected.')
- 测试结果
\ | pymalloc | without-pymalloc | tcmalloc |
---|---|---|---|
list对象数量 | 10000000 | 10000000 | 10000000 |
平均消耗时间 | 21.379s | 21.199s | 20.53s |
run调用期间内存占用 | 3.6g | 3.6g | 3.6g |
run结束后内存占用 | 2.7g | 23m | 8224b |
collect后的内存占用 | 2.7g | 23m | 8224b |
-
结论
pymalloc在一轮暴虐之后进程内存下不去。
不使用pymalloc容易导致不少兼容性的问题出现,而且许多python的新feature会用不了,不建议这么做。
而tcmalloc果然名不虚传,run方法结束后,内存马上释放到解放前。建议生产环境尝试使用tcmalloc编译的Python解释器,其它兼容性的问题有待考证。