我有一个用Python编写并基于Twisted的音频广播服务器。它工作正常,但当服务器上有更多用户时,其内存使用量会增加,但当这些用户下线时,内存使用量不会下降。如下图所示:
你可以看到内存使用曲线在听众/收音机的曲线上升的地方上升,但是在收听者/收音机的峰值之后,内存使用率仍然很高,永远不会下降。
我尝试过以下方法来解决这个问题:
以下是我用于运行扭曲服务器的环境:
guppy转储:
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 不可见的内存使用量,它们是什么?
我的问题是:
答案 0 :(得分:6)
正如我的猜测,这是由于内存碎片问题。最初的设计是将音频数据块保存在列表中,所有这些块都不是固定大小的。一旦缓冲列表的总大小超过缓冲区的限制,它就会从列表顶部弹出一些块来限制大小。它可能看起来像这样:
大多数都大于256字节,Python使用malloc来处理大于256字节的块,而不是使用内存池。你可以想象那些块被分配并释放,会发生什么?例如,当释放1350大小的块时,堆中可能有一个空闲的1350字节空间。在那之后,又来了另一个请求988,一旦malloc拿起洞,然后又有一个362号的新的小自由洞。经过长时间的运行,堆中有越来越多的小洞,换句话说,就是这样堆中的许多碎片。虚拟内存的页面大小通常是4KB,那些片段分布在很大的堆栈范围内,这使得OS无法交换那些页面。因此,RSS始终很高。
在修改了我服务器的音频块管理模块的设计之后,它现在使用很少的内存。您可以看到该图并与之前的图进行比较。
新设计使用bytearray 而不是字符串列表。它是一大块内存,所以没有更多的碎片。
答案 1 :(得分:2)
对我来说,它听起来像C模块中的内存泄漏。 Valgrind是跟踪内存分配相关问题的好工具。我不知道它对运行时加载的模块的效果有多好......
答案 2 :(得分:0)
你有没有想过使用CentOS替代dtrace - SystemTap我认为它被称为。
这应该可以让你对* nix进程中发生的事情有一个非常低级别的跟踪.......在黑暗中刺伤,但可能会让你在进程内活动上更加透明。
有趣的问题。期待看到其他人的回应。
本