我有一个用 Python 编写并基于 Twisted 的音频广播服务器。它工作正常,但是当服务器上有更多用户时,它的内存使用量会增加,但是当这些用户下线时,内存使用量永远不会下降。如下图所示:
你可以看到监听器/ radio 的曲线上升的地方内存使用曲线上升,但是监听器/ radio 的峰值之后,内存使用率仍然很高,从来没有下降过。
我尝试了以下方法来解决这个问题:
- 将 Twisted 从 8.2 升级到 9.0
- 使用 guppy 倾倒大量食物,但完全没有帮助
- 将 selector reactor 切换到 epoll reactor,同样的问题。
- 使用 objgraph 绘制对象关系图,但我看不到点。
这是我用来运行我的扭曲服务器的环境:
- Python:2.5.4 r254:67916
- 操作系统:Linux 版本 2.6.18-164.9.1.el5PAE (mockbuild@builder16.centos.org)(gcc 版本 4.1.2 20080704 (Red Hat 4.1.2-46))
- Twisted:9.0(在 virtualenv 下)
孔雀鱼的垃圾场:
Partition of a set of 116280 objects. Total size = 9552004 bytes.
Index Count % Size % Cumulative % Type
0 52874 45 4505404 47 4505404 47 str
1 5927 5 2231096 23 6736500 71 dict
2 29215 25 1099676 12 7836176 82 tuple
3 7503 6 510204 5 8346380 87 types.CodeType
4 7625 7 427000 4 8773380 92 function
5 672 1 292968 3 9066348 95 type
6 866 1 82176 1 9148524 96 list
7 1796 2 71840 1 9220364 97 __builtin__.weakref
8 1140 1 41040 0 9261404 97 __builtin__.wrapper_descriptor
9 2603 2 31236 0 9292640 97 int
可以看到,总大小9552004字节为9.1 MB,可以看到ps命令报告的rss:
[xxxx@webxx ~]$ ps -u xxxx-o pid,rss,cmd
PID RSS CMD
22123 67492 twistd -y broadcast.tac -r epoll
我的服务器的rss是65.9 MB,这意味着我的服务器中有56.8 MB不可见的内存使用,它们是什么?
我的问题是:
- 如何找到内存使用量增加的原因?
- 什么是 guppy 可见的内存使用情况?
- 那些不可见的内存使用是什么?
- 是不是某些 C 语言模块的内存泄漏造成的?如果是,我该如何追踪和修复它?
- Python 如何管理内存?内存池?我认为这可能是由音频数据 block 引起的。这样在 Python 解释器拥有的内存块中几乎没有泄漏。
2010/1/20 更新: 有趣的是,我下载了最新的日志文件,它显示内存从不增加。我认为可能是分配的内存空间足够大。这是最新的数字。
最佳答案
正如我的猜测,这是由于内存碎片问题。最初的设计是将音频数据 block 保存在一个列表中,它们都不是固定大小的。一旦缓冲列表的总大小超过缓冲区的限制,它会从列表顶部弹出一些 block 来限制大小。它可能看起来像这样:
- block 大小 511
- block 大小 1040
- block 大小 386
- block 大小 1350
- ...
大部分大于 256 字节,Python 使用 malloc 处理大于 256 字节的 block ,而不是使用内存池。你可以想象那些 block 被分配和释放,会发生什么?例如,当释放大小为 1350 的 block 时,堆中可能有 1350 字节的空闲空间。之后又来了一个请求 988,一旦 malloc 捡到了这个洞,然后又多了一个大小为 362 的新的小空洞。经过长时间的运行,堆里的小洞越来越多,也就是说,有这么多堆中的许多碎片。虚拟内存的页面大小通常为 4KB,这些碎片分布在大范围的堆周围,这使得操作系统无法将这些页面交换出去。因此,RSS 总是很高。
我的服务器的音频 block 管理模块的设计修改后,现在它使用的内存很少。您可以看到该图并与上一个进行比较。
新设计使用字节数组而不是字符串列表。这是一大块内存,所以没有更多的碎片。
关于python - 如何找到扭曲服务器内存使用量增加的根源?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2100192/