【问题标题】:Getting stack trace from Perl "Out of memory" error从 Perl“内存不足”错误获取堆栈跟踪
【发布时间】:2011-09-14 22:40:14
【问题描述】:

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) 不知何故让进程持续监控自己的内存,并在内存变高但在“内存不足”错误之前转储堆栈跟踪。

谢谢!

乔恩

【问题讨论】:

  • 是否可以在Devel::NYTProf下运行进程?
  • 就像我说的,这个问题很少发生 - 假设在一个小时的负载测试之后 - 所以如果我们在分析或大量日志记录下运行,我们必须收集大量数据。另外有一个可以在生产中工作的解决方案会很好,显然我们不能在 Devel::NYTProf 下运行。

标签: perl memory out-of-memory


【解决方案1】:

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

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

【讨论】:

  • 谢谢。 C 级回溯中是否真的有足够的信息来确定我们在 Perl 堆栈中的位置,不仅仅是我们所在的代码行,还有调用者等?
  • Jonathan:在某处有,但不一定容易或公开。您可以使用 call_sv/etc(请参阅 perlcall)回调 Perl 以执行 Carp::cluck 的内存限制。
【解决方案2】:

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

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

【讨论】:

  • 有趣。所以理论上我可以创建一个调用 malloc 的 malloc 钩子 (gnu.org/s/hello/manual/libc/Hooks-for-Malloc.html),如果发生 OOM,1) 提高软 VMEM 限制 2) 使用相同的参数重新调用 malloc(现在应该会在更高的限制下成功) 3) 让进程转储 Perl 堆栈跟踪(例如,通过向自身发送 SIGUSR2)
【解决方案3】:
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-22
  • 1970-01-01
  • 2010-10-11
  • 2018-09-19
  • 1970-01-01
  • 1970-01-01
  • 2013-04-18
相关资源
最近更新 更多