Python内存占用与堆大小
我在用一个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的物理内存使用量和堆的大小之间会有这么大的差距呢?
4 个回答
1
你在用哪个版本的Python?
我问这个是因为早期的CPython版本没有释放内存,这个问题在Python 2.5中得到了修复。
3
CPython这个实现只在特殊情况下才会释放分配的内存。这是一个大家都知道的问题,但CPython的开发者对此并没有太多关注。推荐的解决办法是“分叉并结束”占用大量内存的进程。
6
Python 从 C 的内存堆中分配 Unicode 对象。所以当你分配了很多这样的对象(还有其他的内存块),然后释放掉大部分,只留下最后一个时,C 的内存分配不会把内存还给操作系统,因为 C 的内存堆只会在最后缩小,而不会在中间缩小。只有释放掉最后一个 Unicode 对象,才能释放 C 内存堆末尾的那块内存,这样 malloc 才能把所有的内存还给系统。
除了这些问题,Python 还维护了一池已经释放的 Unicode 对象,以便更快地分配内存。所以当最后一个 Unicode 对象被释放时,它并不会立刻还给 malloc,这样就会导致其他的内存页面被卡住。