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

时间:2010-01-20 09:18:31

标签: python memory-leaks memory-management twisted

我有一个用Python编写并基于Twisted的音频广播服务器。它工作正常,但当服务器上有更多用户时,其内存使用量会增加,但当这些用户下线时,内存使用量不会下降。如下图所示: alt text

你可以看到内存使用曲线在听众/收音机的曲线上升的地方上升,但是在收听者/收音机的峰值之后,内存使用率仍然很高,永远不会下降。

我尝试过以下方法来解决这个问题:

  1. 从8.2升级到9.0
  2. 使用guppy转储堆,但根本没有帮助
  3. 将选择器反应器切换到epoll反应器,同样的问题。
  4. 使用objgraph绘制对象关系图,但我无法从中看到点。
  5. 以下是我用于运行扭曲服务器的环境:

    • 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下)

    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 不可见的内存使用量,它们是什么?

    我的问题是:

    1. 如何找到增加内存使用量的来源?
    2. guppy的可见内存使用量是多少?
    3. 那些看不见的内存使用情况是什么?
    4. 是否是由用C编写的某些模块的内存泄漏引起的?如果是,我该如何追踪并修复它?
    5. Python如何管理内存?内存池?我认为这可能是由音频数据块引起的。因此Python解释器拥有的内存块几乎没有泄漏。
    6. 更新2010/1/20 : 有趣的是,我下载了最新的日志文件,它表明内存永远不会增加。我想可能是分配的内存空间足够大。这是最新的数字。 alt text

      更新2010/1/21 : 这是另一个数字。哼......提高一点点 alt text

      哎呀......还在上升 alt text

3 个答案:

答案 0 :(得分:6)

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

  1. 块大小511
  2. 块大小1040
  3. 块大小386
  4. 块大小1350
  5. ...
  6. 大多数都大于256字节,Python使用malloc来处理大于256字节的块,而不是使用内存池。你可以想象那些块被分配并释放,会发生什么?例如,当释放1350大小的块时,堆中可能有一个空闲的1350字节空间。在那之后,又来了另一个请求988,一旦malloc拿起洞,然后又有一个362号的新的小自由洞。经过长时间的运行,堆中有越来越多的小洞,换句话说,就是这样堆中的许多碎片。虚拟内存的页面大小通常是4KB,那些片段分布在很大的堆栈范围内,这使得OS无法交换那些页面。因此,RSS始终很高。

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

    alt text

    新设计使用bytearray 而不是字符串列表。它是一大块内存,所以没有更多的碎片。

答案 1 :(得分:2)

对我来说,它听起来像C模块中的内存泄漏。 Valgrind是跟踪内存分配相关问题的好工具。我不知道它对运行时加载的模块的效果有多好......

答案 2 :(得分:0)

你有没有想过使用CentOS替代dtrace - SystemTap我认为它被称为。

这应该可以让你对* nix进程中发生的事情有一个非常低级别的跟踪.......在黑暗中刺伤,但可能会让你在进程内活动上更加透明。

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