问题描述
|
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,...),以便在关闭服务器之前,该进程以\“ Out of memory \”终止。
我们不知道代码在哪里发生,并且如果不进行数小时的负载测试就很难重现。
我们真正想要的是一种在进程内存耗尽之前获取Perl堆栈跟踪的方法,因此我们知道是什么代码导致了这一点。不幸的是,“内存不足”是无法捕获的错误。
这是我正在考虑的选项,每个选项都有其缺点:
1)使用$ ^ M紧急存储池。要求我们使用-DPERL_EMERGENCY_SBRK和-Dusemymalloc重新编译perl。
2)输入大量的日志语句,然后分析日志以查看该进程在何处停止。
3)编写一个外部脚本,该脚本不断扫描httpd进程池,如果发现其中一个使用大量内存,则向其发送USR2信号(我们已安排该信号转储堆栈跟踪)。
4)以某种方式让进程连续监视自己的内存,并在内存变高但在“内存不足”错误之前转储堆栈跟踪。
谢谢!
乔恩
解决方法
您可以尝试使用LD_PRELOAD加载自定义版本的malloc / free。不必重新链接或重新编译任何内容。只需将LD_PRELOAD设置为具有与.so具有相同接口的.so,在运行可执行文件时,将加载此预加载版本的malloc,而不是常规系统malloc。例如,这是一种有效检测内存错误的常用策略。
我认为efence在这里不适合您,因为这是用于检测内存覆盖,而不是调试内存不足(我不知道它对OOM的作用)。我认为您可能想检查一下failmalloc。我从来没有使用过它,但听起来它可能可以满足您的要求(我只浏览了首页)。
, 您可以通过
mod_backtrace
得到回溯,请参阅Andy Millar的介绍。回溯在C级别上,因此您要么需要
一点点Perl内部知识,只需查看回溯或
要运行gdb,请在crashy函数处设置一个断点,并使用mod_perl书中的gdb宏检查Perl堆栈和词法变量。
, 根据实用mod_perl的说法,在您的代码中添加Apache::Debug level => 4;
将导致其分配$ ^ M紧急池并调用Carp::confess()
。
https://books.google.co.vi/books?id=i3Ww_7a2Ff4C&pg=PT699&lpg=PT699&dq=how+do+i+get+a+stack+trace+when+perl+dies+with+an+out+of+ memory + error&source = bl&ots = Id7ll9Gng2&sig = r8SpZ4jvFfjzfM2eSmoV2DjWLnY&hl = zh-CN&sa = X&ved = 0ahUKEwiwqNitporbAhXow1kKHZo9CRoQ6AEIODAC#v = onepage&q = how%20 %% 20 %% 20 %% 20%20%20%20%20%20%20%20 %% 20do20%20%20%20%20%20%20%20%20%20%20%有20%的球友20错误&f = false