2011-06-14 113 views
5

tl; dr:如何在Perl httpd进程内存不足时转储perl堆栈跟踪。从Perl获取堆栈跟踪“内存不足”错误

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

偶尔和不可预知的是,子httpd进程开始以惊人的速度使用所有可用内存。我们至少使用了BSD :: Resource :: setrlimit(RLIMIT_VMEM,...),这样在关闭服务器之前,进程就会因“内存不足”而死亡。

我们不知道在代码中发生了什么,并且在没有负载测试小时的情况下很难重现。

我们真正想要的是一种在进程内存耗尽之前获得Perl堆栈跟踪的方法,因此我们知道是什么代码导致了这种情况。不幸的是,“内存不足”是untrappable error

这里是我考虑的选项,各自有各自的缺点:使用$^M emergency memory pool

1)。要求我们用-DPERL_EMERGENCY_SBRK和-Dusemymalloc重新编译perl。

2)输入大量的日志语句,然后分析日志以查看过程停止的地方。 3)编写一个不断扫描httpd进程池的外部脚本,如果它看到一个使用大量内存的脚本,则向它发送一个USR2信号(我们已经安排转储堆栈跟踪)。

4)以某种方式持续监视自己的内存,并在内存变高但在“内存不足”错误之前转储堆栈跟踪。

谢谢!

乔恩

+0

是否可以在[Devel :: NYTProf](http://search.cpan.org/perldoc?Devel::NYTProf)下运行该进程? – 2011-06-14 18:53:14

+0

就像我说的那样,这个问题很少发生 - 比如在一小时的负载测试之后 - 所以如果我们运行在性能分析或重度日志记录的情况下,我们将不得不收集大量的数据。另外,解决方案可以在生产环境中工作,显然,我们无法在Devel :: NYTProf下运行。 – 2011-06-14 19:07:23

回答

2

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

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

+0

有趣。因此,理论上我可以创建一个调用malloc的malloc钩子(http://www.gnu.org/s/hello/manual/libc/Hooks-for-Malloc.html),如果发生OOM,则可以调用 1)raise软VMEM限制 2)再调用malloc使用相同的参数(现在应该有更高的极限成功) 3)获得转储Perl的堆栈跟踪的过程中(例如,通过将自身发送一个SIGUSR2) – 2011-06-14 21:35:38

3

您可以使用mod_backtrace进行回溯,请参阅Andy Millar's introduction。回溯是C级,让你无论是需要

  • 一点的Perl的内部构件知识来推断Perl的堆栈通过简单地看回溯或
  • 运行GDB,在crashy功能设置断点并使用mod_perl书中的gdb宏来检查Perl堆栈和词法变量。
+0

感谢。在C语言级别的回溯中是否有足够的信息来确定我们在Perl堆栈中的位置,而不仅仅是我们所在的代码行,而是调用者等等? – 2011-06-14 21:26:06

+0

乔纳森:在某个地方,但这不一定很容易或公开。您可以使用call_sv/etc(请参阅perlcall)回调Perl,以便为您的内存限制做一个Carp :: cluck。 – tsee 2011-06-15 05:12:50