如何使用GDB分析崩溃转储文件

8
我有一个在Cent OS上运行的服务器应用程序。该服务器每秒响应许多请求,但每隔一小时左右就会重复崩溃并创建一个崩溃转储文件。情况非常糟糕,我需要尽快找出崩溃原因。
我怀疑问题是并发问题,但我不确定。我可以访问源代码和崩溃转储文件,但我不知道如何使用崩溃转储文件来确定问题。
非常感谢您的任何建议。
4个回答

11

首先,需要看一下程序崩溃时出现的错误信息。这通常会告诉你发生了什么样的错误。例如,“segmentation fault”或“SIGSEGV”几乎肯定意味着您的程序已经解引用了一个空指针或其他无效指针。如果程序是用C++编写的,那么错误消息通常会告诉您任何未捕获异常的名称。

如果您没有看到错误消息,则可以从命令行运行程序,或将其输出导入文件。

为了使核心文件真正有用,您需要在没有优化且带有调试信息的情况下编译程序。GCC需要以下选项:-g -O0。(确保您的构建没有任何其他-O选项。)

获取到核心文件后,使用以下命令在gdb中打开:

gdb YOUR-APP COREFILE

输入where命令以查看崩溃发生的位置。您实际上处于普通的调试会话中-您可以检查变量、上下移动堆栈、在线程之间切换等。

如果您的程序崩溃了,那么很可能是无效的内存访问-因此您需要查找具有零值或指向糟糕数据的指针。您可能不会在堆栈的最底层找到问题,您可能需要向上移动几个级别才能找到问题。

祝你好运!


9
如果问题需要一个小时左右才能显现出来,那么可能是内存问题——可能是内存不足,或者可能是内存被践踏(例如使用已经释放的内存)。
你说你有崩溃转储文件——那是核心转储吗?
假设你有一个核心转储,那么第一步应该是打印堆栈回溯:
gdb program core
> where

这应该告诉您程序在崩溃时所在的位置。其他可用信息取决于服务器的编译方式。如果可能的话,您应该重新编译并启用调试(使用GCC的'-g'标志)。这将从堆栈回溯中提供更多信息。

如果您的问题与内存有关,请考虑使用valgrind运行。

还要考虑构建和运行带有调试版本的malloc()。调试版本将检测到正常版本忽略或崩溃的内存滥用。


谢谢您详细的回答。服务器已经编译了调试信息,当它崩溃时会创建一个核心转储文件。服务器初始化许多线程。每当线程数少于200时,该服务器将继续工作一个多小时,但是当请求数量增加并将线程池中的线程数量增加到约300个时,服务器很快就会崩溃。能否请您告诉我如何使用调试版本的malloc可以帮助解决问题? - red.clover
关于“调试malloc”:如果问题是内存滥用,那么调试malloc将通过记录有关分配空间的更多信息来帮助,通常是通过分配更多空间来实现的,因此当其函数被调用时,它们可以更早地发现各种内存滥用 - 限制所造成的损害并通常使其更容易发现问题。例如,如果您释放了已经释放的内存块,它可以报告这一点-而不仅仅是接受您的释放并使用实际不存在的信息。请参阅K&R以获取简单的malloc()实现。 - Jonathan Leffler
关于“200个线程以下可以,超过300个就会崩溃”的问题,您是否考虑过服务器是否分配了一些资源的固定大小池(可能是200个,也可能是256个),并且没有正确检查该资源的耗尽情况。这可能是一组互斥锁、信号量或其他触发内存滥用的东西。服务器代码是您编写的吗?您应该考虑限制工作线程的数量吗? - Jonathan Leffler
很不幸,我并没有编写这段代码,所以我真的不知道服务器上到底发生了什么。我只负责稳定服务器,但不幸的是编写它的人现在不可用。资源耗尽的想法是一个好主意。我会尝试找到可能导致此问题的任何资源,并尝试使用调试malloc解决方案。希望它能向我展示崩溃的真正原因。非常感谢您的帮助。 - red.clover

6
gdb -c core.file exename
bt

假设 exename 是用调试符号构建的(所有动态依赖项均在路径中),这将为您提供回溯信息。 'up'和'down'将使您在堆栈中向上或向下移动,并且可以使用p varname来检查本地变量和参数。你也可以尝试在 valgrind 下运行它:
valgrind --tool=memcheck --leak-check=full exename

0

你的应用程序是否创建了核心文件?如果是,我建议使用gdb来调试此问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接