Python JSON 内存膨胀

5 投票
1 回答
4280 浏览
提问于 2025-04-16 20:35
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的版本有所不同)。所以阈值没有达到,因此没有进行内存回收。

这就是基于阈值的垃圾回收调度的典型行为。如果你需要及时将空闲内存返回给操作系统,那么你需要把基于阈值的调度和基于时间的调度结合起来(也就是说,在上次回收后经过一定时间后请求再次进行内存回收,即使阈值还没有达到)。

撰写回答