Python内存占用量与堆大小

时间:2009-07-28 14:19:10

标签: python memory-leaks solr

在使用python脚本发出大型 solr 查询时,我遇到了一些内存问题。我正在使用 solrpy 库与solr服务器进行交互。该查询返回大约80,000条记录。发出查询后,立即通过顶部气球查看python内存占用量达到~190MB。

 PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND 
8225 root      16   0  193m 189m 3272 S  0.0 11.2   0:11.31 python
...

此时,通过heapy查看的堆配置文件如下所示:

Partition of a set of 163934 objects. Total size = 14157888 bytes.   
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0  80472  49  7401384  52   7401384  52 unicode
     1  44923  27  3315928  23  10717312  76 str
...

unicode对象表示查询中记录的唯一标识符。需要注意的一点是,总堆大小只有14MB,而python占用了190MB的物理内存。一旦存储查询结果的变量超出范围,堆配置文件就会正确反映垃圾收集:

Partition of a set of 83586 objects. Total size = 6437744 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0  44928  54  3316108  52   3316108  52 str

但是,内存占用量保持不变:

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 8225 root      16   0  195m 192m 3432 S  0.0 11.3   0:13.46 python
...

为什么python的物理内存占用量与python堆的大小之间存在如此大的差异?

4 个答案:

答案 0 :(得分:5)

Python从C堆中分配Unicode对象。所以当你分配它们中的许多(以及其他malloc块),然后释放它们中的大部分除了最后一个,C malloc将不会向操作系统返回任何内存,因为C堆只会在最后收缩(不在中间)。释放最后一个Unicode对象将在C堆的末尾释放该块,然后允许malloc将其全部返回给系统。

除了这些问题之外,Python还维护一个释放的unicode对象池,以便更快地进行分配。因此,当释放最后一个Unicode对象时,它不会立即返回到malloc,使所有其他页面卡住。

答案 1 :(得分:2)

CPython实现只有异常免费的分配内存。这是一个众所周知的错误,但它并没有得到CPython开发人员的太多关注。建议的解决方法是“分叉并消耗”占用大量RAM的进程。

答案 2 :(得分:1)

你使用的是什么版本的python?
我问的是older version of CPython did not release the memory,这在Python 2.5中得到了解决。

答案 3 :(得分:0)

我实施了hruske的“fork and die”的建议。我正在使用os.fork()在子进程中执行代码的内存密集部分,然后我让子进程退出。父进程对子进程执行os.waitpid(),以便在给定时间只执行一个线程。

如果有人发现这个解决方案存在任何陷阱,请加入。