Python JSON 内存膨胀
import json
import time
from itertools import count
def keygen(size):
for i in count(1):
s = str(i)
yield '0' * (size - len(s)) + str(s)
def jsontest(num):
keys = keygen(20)
kvjson = json.dumps(dict((keys.next(), '0' * 200) for i in range(num)))
kvpairs = json.loads(kvjson)
del kvpairs # Not required. Just to check if it makes any difference
print 'load completed'
jsontest(500000)
while 1:
time.sleep(1)
在Linux系统中,使用top命令可以看到,执行完'jsontest'函数后,python进程占用了大约450Mb的内存。如果不调用json.loads,就不会出现这个问题。在执行完这个函数后,调用gc.collect可以释放内存。
看起来这些内存并不是被缓存或者python内部的内存分配器占用,因为明确调用gc.collect后内存是被释放的。
这是不是因为垃圾回收的阈值(700, 10, 10)从来没有达到过呢?
我在jsontest后面加了一些代码来模拟这个阈值,但并没有帮助。
1 个回答
3
把这个放在你程序的最上面
import gc
gc.set_debug(gc.DEBUG_STATS)
这样每当有内存回收的时候,你就会看到输出结果。在你的示例代码中,jsontest
完成后没有进行内存回收,直到程序退出。
你可以放入
print gc.get_count()
来查看当前的内存使用情况。第一个数字是自上次进行0代内存回收以来,分配的内存超过释放的内存的数量;第二个(和第三个)是自上次进行1代(和2代)内存回收以来,0代(和1代)被回收的次数。如果你在jsontest
完成后立即打印这些数字,你会看到结果是(548, 6, 0)
或类似的数字(这可能会根据Python的版本有所不同)。所以阈值没有达到,因此没有进行内存回收。
这就是基于阈值的垃圾回收调度的典型行为。如果你需要及时将空闲内存返回给操作系统,那么你需要把基于阈值的调度和基于时间的调度结合起来(也就是说,在上次回收后经过一定时间后请求再次进行内存回收,即使阈值还没有达到)。