如何查找扭曲服务器内存使用量增加的来源?

问题描述:

我有一个用Python编写的基于Twisted的音频广播服务器。它工作正常,但是当服务器上有更多的用户时,它的内存使用量正在增加,但是当这些用户离线时内存使用率永远不会下降。正如你在下面的图中看到: alt text http://static.ez2learn.com/temp/mem_figure3.svg如何查找扭曲服务器内存使用量增加的来源?

你可以看到内存使用情况的曲线上升,其中听众/收音机的曲线上升,但听者/收音机的峰值之后,内存使用率仍然很高,从来没有下跌降落。

我曾尝试以下解决这个问题的方法:

  1. 升级扭曲的从8.2到9.0
  2. 使用孔雀转储heapy,但在所有
  3. 切换选择器无助于EPOLL同样的问题。
  4. 使用objgraph绘制对象关系图,但我看不到点。

这里是我用来运行我的扭曲的服务器环境:

  • 的Python:2.5.4 R254:67916
  • 操作系统:Linux版本2.6.18-164.9.1.el5PAE(mockbuild @ builder16.centos.org)(gcc版本4.1.2 20080704(红帽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:

[[email protected] ~]$ 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我的服务器中的隐藏内存使用情况,它们是什么?

我的问题是:

  1. 如何找到提高内存使用的来源是什么?
  2. 可怕的内存使用情况是什么?
  3. 那些看不见的内存使用情况是什么?
  4. 是由C写的一些模块的内存泄漏引起的?如果是这样,我该如何追踪和修复?
  5. Python如何管理内存?内存池?我认为这可能是由音频数据块引起的。所以Python解释器拥有的内存块中几乎没有泄漏。

更新2010年1月20日: 这很有趣,我下载最新的日志文件,它表明记忆永远不会从一个时刻增加。我想可能是分配的内存空间够大。这是最新的数字。 alt text http://static.ez2learn.com/temp/mem_figure4.svg

更新2010/1/21: 这里的另一个人物。哼....提高一点点 alt text http://static.ez2learn.com/temp/mem_figure6.svg

抱歉...仍在上升 alt text http://static.ez2learn.com/temp/mem_figure7.svg

+0

重新更新:即使您的#用户正在关闭,它仍在不断增长,所以我不会称这种好的行为。很高兴知道它不会继续下去,直到发生死亡交换... – Wim 2010-01-20 23:54:03

+0

服务器正在真实环境下运行,在这种情况下很难找到原因。我需要一些时间来简化我的程序,并构建模拟器和测试工具,以便我可以在可测试的环境中运行服务器。一旦完成工作,我会报告所看到的。 – 2010-01-21 10:51:48

正如我猜测,这是由于内存碎片问题。原始设计是将音频数据块保存在一个列表中,它们都不是固定的大小。一旦缓冲列表的总大小超过了缓冲区的限制,它会从列表顶部弹出一些块来限制大小。它可能看起来像这样:

  1. 块的大小511
  2. 块大小1040
  3. 块大小386
  4. 块大小1350
  5. ...

他们中的大多数是大超过256字节,Python使用malloc作为大于256字节的块,而不是使用内存池。你可以想象这些块被分配和释放,会发生什么?例如,当1350大小的块被释放时,堆中可能有1350个空闲空间。之后,再来一次请求988,一旦malloc拿起这个洞,然后又有一个新的小小的*洞362.长时间运行后,堆中出现越来越多的小洞,换句话说,就是这样堆中有许多碎片。虚拟内存的页面大小通常为4KB,这些片段分布在大范围的堆中,这使得操作系统无法将这些页面交换出去。因此,RSS总是很高。

在修改了我的服务器的音频块管理模块的设计之后,它现在使用的内存很少。你可以看到图形并与之前的图形进行比较。

alt text http://static.ez2learn.com/temp/new_mem_figure.svg

新的设计使用字节组而不是字符串的名单。这是一大块记忆,所以没有更多的碎片。

你有没有想过使用CentOS的”替代的DTrace - SystemTap我认为它叫。

这应该给你什么是你的* nix的过程中发生了一个相当低的水平痕迹.......在黑暗中刺,但可能给你进程内活动有一定的透明度。

虽然有趣的问题。期待看到其他人的回应。

它听起来像一个C模块中的内存泄漏给我。 Valgrind是跟踪内存分配相关问题的好工具。我不知道它有多好,虽然与运行时加载的模块工作...