python2不愿意释放内存吗?

时间:2013-12-17 10:45:45

标签: python linux python-2.7 memory python-internals

我知道python有自己的内存管理实现,使用不同大小和更多对象的areans,虽然我还没有找到完整的文档。 我仍然想了解幕后发生的事情。

后台是一个长期运行的python2数据库应用程序,它不知何故泄漏内存,它运行在64位Linux上。 每天这个应用程序都会读取数据库中的一些数据,它总计达到~3.5GB的RAM用量,只是为了读取行(使用MySQLdb)。大约有3.5M行,之后减少到几百行,剩下的就超出了范围(“释放”)。

但是python-2.7只释放了现在“未使用”内存的一小部分。我很害怕以后重用内存,但我观察到这种内存似乎“慢慢泄漏”。上面提到的数据库应用程序每天都会读取这一大块数据。连续读取两次(或多次)只为第一次读取分配内存,然后显然重用了这个内存。但让它运行几个小时,然后再次读取数据库数据会产生下一个3 + GB的内存分配峰值(再次永远不会被释放)。

要添加更多背景(并使事情更难解释),我必须说这个数据库应用程序不是空闲但是永久执行任务。我很确定通过监视内存使用情况(nagios性能数据),如果没有这个特定的数据库查询,内存使用量永远不会攀升到3.5GB RAM(甚至接近)。但启用此查询每天会增加3 + GB RAM。 有问题的查询主要返回唯一的整数和浮点数。

这是我开始怀疑python的主要原因。我觉得我已经阅读了大量的信息,看了_PyObject_DebugMallocStats(),但不知道python决定保留几千兆字节的原因(或原因)。

归结为一个非常简单的例子(不代表有关数据的真实情况,我知道xrange()):

def mem_usage(pid=None):
    mem = 0
    proc = str(pid or "self")
    with open("/proc/%s/smaps" % proc) as fstat:
        for l in fstat:
            if not l.startswith("Private_"):
                continue
            mem += int(l.split(":", 1)[1].strip().split(" ", 1)[0])
    return mem

mem_usage()                 # reports a few MB
x = list(range(100000000))  # use list() for py3k
mem_usage()                 # reports ~3GB
del x
mem_usage()                 # reports ~2.5GB

有趣的是,当我删除庞大的列表时,py3k会释放内存。不仅是一小部分,而且几乎所有的内存使用量都只比开始时略高一些。

我已经用memory_profiler进行了调查(我猜它没有比给定的mem_usage()函数做得多)没有任何见解。我已经阅读了关于gdb-heap但是到目前为止无法使用它。

我实际上不相信有解决方案(除了重新启动应用程序或减少从数据库读取的数据量)。但我真的很感激有关这一主题的任何见解。

编辑:

总结一下我的问题:为什么python-2.7会保留这个内存?

1 个答案:

答案 0 :(得分:2)

range示例保留了大量内存,因为Python 2.7永远不会释放int s:

  

block_list is a singly-linked list of all PyIntBlocks ever allocated, linked via their next members. PyIntBlocks are never returned to the system before shutdown (PyInt_Fini).

然而,这应该不是问题,除非在某些时候,几千兆字节的同时存在。否则,Python将使用旧的,丢弃的int来表示您使用的任何新的int。如果你有几千兆字节的实时内容,我建议你找一种方法来保持较少的内容。