Python JSON 内存膨胀问题

5
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的RAM。如果省略对“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版本而异)。因此,阈值未达到,没有进行垃圾回收。

这是基于阈值的垃圾回收调度的典型行为。如果您需要及时将空闲内存返回给操作系统,则需要将基于阈值的调度与基于时间的调度相结合(也就是说,在自上次收集以来经过一定时间后请求进行另一次收集,即使未达到阈值)。


即使我们多次调用jsontest,内存仍保持在约450MB左右。这是上一个jsontest调用使用的内存吗?此代码是Web应用程序的一部分,用于处理JSON消息。即使运行Web应用程序一小时后,内存似乎也没有被释放。除了gc.collect之外,是否有其他解决方法? - Anoop
2
在每次调用 jsontest 后尝试打印 gc.get_count(),一切都会变得清晰明了。此外,调用 gc.collect 有什么问题吗? - Gareth Rees

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接