从Perl“Out of memory”错误获取堆栈跟踪

时间:2011-06-14 18:20:49

标签: perl memory out-of-memory

tl; dr:当Perl httpd进程内存不足时,如何转储perl堆栈跟踪。

我们有一台mod_perl 2服务器,Perl 5.8.8,RHEL 5.6,Linux 2.6.18。

非常偶然且不可预测,子httpd进程开始以惊人的速度耗尽所有可用内存。我们至少使用过BSD :: Resource :: setrlimit(RLIMIT_VMEM,...),因此在关闭服务器之前,进程会因“内存不足”而死亡。

我们不知道代码在哪里发生,如果没有数小时的负载测试就很难重现。

我们真正喜欢的是在进程耗尽内存之前获取 Perl堆栈跟踪的方法,因此我们知道导致此问题的代码。不幸的是,“内存不足”是untrappable error

以下是我正在考虑的选项,每个选项都有其缺点:

1)使用$^M emergency memory pool。要求我们使用-DPERL_EMERGENCY_SBRK和-Dusemymalloc重新编译perl。

2)放入大量日志语句,然后分析日志以查看流程停止的位置。

3)编写一个不断扫描httpd进程池的外部脚本,如果它看到一个使用大量内存的脚本,则向它发送一个USR2信号(我们已安排转储堆栈跟踪)。

4)不知何故,进程会持续监视自己的内存,并在内存变高但“内存不足”错误之前转储堆栈跟踪。

谢谢!

乔恩

3 个答案:

答案 0 :(得分:3)

您可以使用mod_backtrace获得回溯,请参阅Andy Millar's introduction。回溯是在C级别,所以你需要

  • 通过简单地查看回溯来推断Perl堆栈的一些Perl内部知识或
  • 运行gdb,在crashy函数中设置断点,并使用mod_perl book中的gdb宏检查Perl堆栈和词法变量。

答案 1 :(得分:2)

您可以尝试使用LD_PRELOAD加载malloc / free的自定义版本。没有必要重新链接或重新编译任何东西。只需将LD_PRELOAD设置为具有与malloc相同的接口的.so,并且在运行可执行文件时将加载此预加载版本的malloc而不是正常的系统malloc。例如,这是使用efence检测内存错误的常用策略。

我不认为efence在这里对你有用,因为那是用于检测内存覆盖,而不是调试内存不足(我不知道它在OOM上做了什么)。我想你可能想看看failmalloc。我从来没有使用过这个,但听起来它可能会做你想要的(我只是浏览了头版)。

答案 2 :(得分:0)