为什么会生成核心转储文件?

19
有时候在我结束程序时,使用Ctrl+\组合键会导致生成一个以core.*命名的核心转储文件。程序不是突然终止,也没有出现分段错误。我认为这是因为收到了SIGQUIT信号,而不是SIGABRTSIGSEGV信号。如果我尝试使用Ctrl+CCtrl+Z,则不会生成此文件。
有人能告诉我为什么只有按下Ctrl+\才会生成该文件吗?如何避免生成该核心转储文件?这个核心转储文件有什么用处吗?

当你说“运行我的代码”时,你是指运行make时还是运行已编译的二进制文件时? - harto
1
只是一点小提示:至少有一个答案解释了为什么SIGINT不会创建核心,但我一开始没有看到任何关于SIGTSTP的讨论(这是默认情况下ctrl + z的作用)-它会暂停进程。 shell内置命令*jobs将向您显示已暂停的进程。还可以查看help fg(如果至少使用bash,则会起作用)。您还可以通过命令kill -SIGTSTP <pid>*生成此内容。还要注意,您可以重新定义默认发送的控制组合(也就是说,如果您想,可以将SIGTSTP定义为ctrl + j)。 *stty -a*将向您显示配置和其他信息。 - Pryftan
7个回答

26

当程序发生故障时,由于操作系统内的错误而终止导致该进程转储核心。最典型的原因是程序访问了无效的指针值。如果您有零星的转储,那么很可能是使用了未初始化的指针。

您能否发布导致故障的代码?除了模糊的概括之外,没有实际看到代码很难猜出问题所在。

至于什么是核心转储,请查看此维基百科文章:


8
在Linux系统中,即使程序没有故障并且在终止时正常运行,按下Ctrl + \也会导致核心转储(core dump)。 - ely
更具体地说,当进程超出其内存空间(读/写)时,就会出现问题。另一个原因是(尽管我不排除这可能是指针相关错误的建议),似乎会发生随机崩溃:进程覆盖了内存但没有超出其内存空间。然后在进程中的某个时间点,长时间之后才会出现错误,你会得到一个损坏的堆栈。它可能会引起各种问题,并且可能很难跟踪 - 尽管这是修订控制可以帮助解决的问题,以及经验。 - Pryftan
如果配置为 SIGQUIT 是的话(默认情况下是这样),但这是因为 SIGQUIT 的默认处理程序是转储核心。如果我没记错的话,忽略 SIGQUIT 不会引发 UB,这意味着你可以防止它。 - Pryftan

13

正如其他人所说,核心转储是程序故障的结果。

您可以使用ulimit命令配置是否生成核心转储。输入

ulimit -c 0

禁用当前Shell中的核心文件生成。

如果生成core文件的程序带有符号信息,您可以使用以下方式进行事后调试会话

gdb <pathto/executable> --core <corefilename>

9

ctrl + \会向进程发送信号SIGQUIT。根据POSIX.1标准,此信号的默认操作是生成一个核心转储文件。

SIGILL、SIGABRT、SIGFPE和SIGSEGV是系统生成核心转储文件的其他情况。

请在您的系统上参考“man 7 signal”以获取更多详细信息。


应该注意的是,除了您提到的SIGILL之外,还有SIGKILL。 SIGKILL默认情况下不会生成核心转储文件,但与SIGSTOP一样,它无法被捕获,忽略或阻止。我指出这一点是因为很容易将SIGILL读作SIGKILL - 尤其是如果您不知道两者都存在。 - Pryftan
关于信号处理程序的注意事项 UB: 根据 POSIX,如果一个进程忽略了一个不是由 kill(2) 或 raise(3) 生成的 SIGFPE、SIGILL 或 SIGSEGV 信号,则该进程的行为是未定义的。整数除以零的结果是未定义的。在某些体系结构上,它将生成一个 SIGFPE 信号。(同时,将最小负整数除以-1可能会生成 SIGFPE。) 忽略此信号可能会导致无限循环。 - Pryftan

8

当进程接收到某些信号时,例如SIGSEGV(内核在访问超出其地址空间的内存时发送的信号),会生成核心转储。通常这是由于指针使用错误导致的。这意味着程序中存在错误。

核心转储对于查找错误很有用。它是问题发生时进程内存的图像,因此可以使用诸如gdb之类的调试器来查看程序当时的运行情况。调试器甚至可以访问程序中变量的值(有时)。

您可以使用ulimit命令防止生成核心转储。


6

这是一个辅助调试不正常应用程序的工具。它很大,因为它包含了应用程序在崩溃时所有物理内存的内容,以及所有线程的寄存器状态和堆栈。

当内核因为某些恶意行为(如生成分段错误或总线错误)而终止应用程序时,会生成这些内容。


嗯...它只包含进程内存的转储,但仍然可能是相当大量的内存。 - Ben
“邪恶”?这意味着犯错误是“邪恶”的吗?也许这是有意的夸张,但那是一个巨大的夸张。而且大小取决于进程(文件)的大小。从技术上讲,“它”并不会直接生成段错误,而是触发了一个段错误。 - Pryftan

3
你可以通过编写不会崩溃的代码来避免创建核心转储文件 :)
说真的,核心转储很有用,因为你可以看到程序在崩溃时的状态,进行“事后”调试。你可以在gdb中打开它们并检查程序的状态(特别是如果它是使用调试构建的)。
如果程序发生了SIGSEGV(通常是由于无效指针引用引起的),SIGABRT(如果你调用了abort(),或者在C++中由于析构函数等异常的默认terminate()处理程序)或其他故障,通常会产生核心转储。你也可以使用调试器或编程方式显式触发它们。
如果你已经修复了所有的错误并且它是完美的,你可以删除它们。此外,如果你以任何方式更改了程序(并重新编译了它),那么它们将变得无用,因为调试信息现在将不匹配核心转储中的内容,因此你可以随时将它们删除。

实际上,即使您不重新编译,这也会发生,因为源文件的行信息不再匹配。因此,如果您通过使用核心转储进行调试,如果更改源代码,则有可能非常错误。即使是一行代码也可能会使事情变得复杂。 - Pryftan

1
Ctrl + \ 的作用是生成核心转储文件,这就是 SIGQUIT 的作用。如果您不想生成它,请改用 Ctrl + CSIGINT)。如果所涉及的程序未响应于 SIGINT 但您需要从终端杀死它,则您或开发人员可能存在问题。

设计为不使用 Ctrl + C 终止的程序应仍对 SIGTERM 做出合理响应,可以通过另一个终端使用 kill -TERM ... 触发它。如果一切都失败了,SIGKILL 将强制立即终止程序。


或更改SIGQUIT的默认行为。 - Pryftan

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