我有一个用Python编写并基于Twisted的音频广播服务器.它工作正常,但当服务器上有更多用户时,其内存使用量会增加,但当这些用户下线时,内存使用量不会下降.如下图所示: alt text http://static.ez2learn.com/temp/mem_figure3.svg
你可以看到内存使用曲线在听众/收音机的曲线上升的地方上升,但是在收听者/收音机的峰值之后,内存使用量仍然很高,永远不会下降.
我试过以下方法来解决这个问题:
升级扭曲从8.2到9.0
使用孔雀鱼转储堆积,但根本没有帮助
将选择器反应器切换到epoll反应器,同样的问题.
使用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))
扭曲: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的隐形内存使用量,它们是什么?
我的问题是:
如何找到增加内存使用量的来源?
孔雀鱼的可见内存使用量是多少?
那些看不见的内存使用是什么?
这是由用C编写的一些模块的内存泄漏引起的吗?如果是,我该如何追踪并修复它?
Python如何管理内存?内存池?我认为这可能是由音频数据块引起的.因此Python解释器拥有的内存块几乎没有泄漏.
更新2010/1/20:有趣的是,我下载了最新的日志文件,它表明内存永远不会增加.我想可能是分配的内存空间足够大.这是最新的数字. alt text http://static.ez2learn.com/temp/mem_figure4.svg
更新2010/1/21:这里的另一个数字.哼......提高一点点 alt文本http://static.ez2learn.com/temp/mem_figure6.svg
哎呀...还在上面的 文字http://static.ez2learn.com/temp/mem_figure7.svg
正如我的猜测,这是由于内存碎片问题.最初的设计是将音频数据块保存在列表中,所有这些块都不是固定大小的.一旦缓冲列表的总大小超过缓冲区的限制,它就会从列表顶部弹出一些块来限制大小.它可能看起来像这样:
块大小511
块大小1040
块大小386
块大小1350
...
其中大多数都大于256字节,Python使用malloc来处理大于256字节的块而不是使用内存池.你可以想象那些块被分配并释放,会发生什么?例如,当释放1350大小的块时,堆中可能有一个空闲的1350字节空间.在那之后,又来了另一个请求988,一旦malloc拿起洞,然后还有另一个362号的新小洞.经过长时间的运行,堆中有越来越多的小洞,换句话说,就是这样堆中的许多碎片.虚拟内存的页面大小通常是4KB,那些片段分布在很大的堆栈范围内,这使得OS无法交换那些页面.因此,RSS始终很高.
在修改了我的服务器的音频块管理模块的设计之后,它现在使用很少的内存.您可以看到该图并与之前的图进行比较.
alt text http://static.ez2learn.com/temp/new_mem_figure.svg
新设计使用bytearray而不是字符串列表.它是一大块内存,所以没有更多的碎片.