【问题标题】:Why are core dump files generated?为什么会生成核心转储文件?
【发布时间】:2009-04-22 05:51:21
【问题描述】:

有时当我运行我的代码时,当我通过 Ctrl+\ 终止程序时会生成一个核心转储文件。文件名的格式为core.*。程序没有突然终止,也没有分段错误。我相信是SIGQUIT 而不是SIGABRTSIGSEGV。如果我尝试 Ctrl+CCtrl+Z,则不会生成。

谁能说出为什么只有在按下 Ctrl+\ 时才会生成它?如何避免生成此核心转储文件?核心转储文件有什么用吗?

【问题讨论】:

  • 当你说“运行我的代码”时,你是在说你运行make的时候吗?或者当你运行编译后的二进制文件时?
  • 只是一个花絮:至少有一个答案解释了为什么 SIGINT 不创建核心但我乍一看没有看到任何关于 SIGTSTP 的讨论(这是 ctrl + z 默认所做的) - 它暂停过程。内置的 shell jobs 将显示暂停的进程。另请参阅 help fg (如果使用 bash 至少会起作用)。您也可以通过以下命令生成它:kill -SIGTSTP <pid>。另请注意,您可以重新定义默认发送的控制组合(即:如果您愿意,可以将 SIGTSTP 定义为 ctrl + j)。 stty -a 将向您显示配置 - 和其他信息。

标签: linux coredump


【解决方案1】:

当由于程序故障而被操作系统终止时,进程会转储内核。发生这种情况的最典型原因是程序访问了无效的指针值。鉴于您有一个零星的转储,很可能您使用的是未初始化的指针。

你能发布导致错误的代码吗?除了模糊的概括之外,如果没有实际看到代码,很难猜测出什么问题。

至于什么是核心转储,请查看这篇 Wikipedia 文章:

【讨论】:

  • 在 Linux 中,Ctrl + \ 会导致核心转储,即使程序没有故障并且在终止时运行良好。
  • 更具体地说,是进程耗尽其内存空间(读/写)。另一个原因(尽管我并不否认这可能是与指针相关的错误)看似随机的崩溃可能会发生:进程覆盖内存但不会超出其内存空间。然后在错误发生很久之后的过程中,你会得到一个废弃的堆栈。它可能会导致各种问题,并且可能是追查的噩梦 - 尽管修订控制可以帮助解决问题和经验。
  • @ely 如果配置为 SIGQUIT 是(默认情况下是)。但这是因为 SIGQUIT 的默认处理程序是转储核心。 Iirc 它不会引起 UB 忽略 SIGQUIT,这意味着您可以防止这种情况发生。
【解决方案2】:

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

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

ulimit -c 0

在活动外壳中禁用核心文件生成。

如果生成核心的程序是使用符号信息构建的,您可以像这样执行post mortem debugging session

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

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

      【解决方案4】:

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

      SIGILL、SIGABRT、SIGFPE、SIGSEGV 是系统将生成内核的其他情况。

      有关详细信息,请参阅您系统上的“man 7 signal”。

      【讨论】:

      • 是的。应该注意的是,除了您所拥有的 SIGILL 之外,还有 SIGKILL。 SIGKILL 默认情况下不会生成核心转储,但就像 SIGSTOP 一样,它不能被捕获、忽略或阻止。我指出这一点是因为很容易将 SIGILL 理解为 SIGKILL - 特别是如果您不知道两者都存在。
      • 关于信号处理程序注意 UB:根据 POSIX,进程在忽略不是由 kill(2) 生成的 SIGFPE、SIGILL 或 SIGSEGV 信号或提高(3)。整数除以零有未定义的结果。在某些架构上,它会生成一个 SIGFPE 信号。 (同样将最大负整数除以 -1 可能会生成 SIGFPE。)忽略此信号可能会导致无限循环。
      【解决方案5】:

      这是一个帮助调试表现不佳的应用程序的工具。它很大,因为它包含了所有应用程序物理内存在其死亡时的内容,以及所有线程的寄存器状态和堆栈。

      当内核终止应用程序做坏事时会生成它们,例如生成分段违规或总线错误。

      【讨论】:

      • 嗯...它只包含进程内存的转储,但仍然可以是相当多的内存。
      • '邪恶'?这意味着犯错是“邪恶的”。也许这是故意夸张,但这是一个巨大的夸张。并且大小因进程(文件)的大小而异。从技术上讲,“它”本身不会产生段错误,而是会触发一个。
      【解决方案6】:

      您可以通过编写不会崩溃的代码来避免创建核心转储文件 :)

      说真的,核心转储很有用,因为您可以看到程序崩溃时的状态,以进行“事后”调试。您可以在 gdb 中打开它们并检查程序的状态(特别是如果它是通过调试构建的)。

      如果程序有 SIGSEGV(通常由无效的指针取消引用引起)、SIGABRT(如果您调用 abort() 或在 C++ 中由默认的 terminate() 处理程序处理析构函数等中的异常,则通常会进行核心转储) 或其他故障。您还可以使用调试器或以编程方式显式触发它们。

      如果你已经修复了所有的错误并且它是完美的,你可以删除它们。此外,如果您以任何方式更改了程序(并重新编译了它),那么它们将变得无用,因为现在的调试信息与核心转储中的内容不匹配,因此您也可以删除它们。

      【讨论】:

      • 实际上即使不重新编译也会出现这种情况,因为源文件的行信息不再匹配。因此,如果您使用 coredump 进行调试,如果您更改源代码,则可能会非常错误。即使是一行也可能使事情复杂化。
      【解决方案7】:

      Ctrl + \ 的作用是生成核心转储。这就是SIGQUIT 所做的。如果您不想生成它,请改用 Ctrl + C (SIGINT)。如果有问题的程序没有响应SIGINT,但您需要从终端杀死它,那么您或开发人员做错了什么。

      被设计为 not 以使用 Ctrl + C 从终端杀死的程序仍应优雅地响应 SIGTERM,这可以被触发通过kill -TERM ... 在另一个终端中。如果一切都失败了,SIGKILL 将强制立即终止。

      【讨论】:

      • 或者改变SIGQUIT的默认行为。
      猜你喜欢
      • 1970-01-01
      • 2021-12-27
      • 2011-12-05
      • 2021-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-19
      • 2014-01-24
      相关资源
      最近更新 更多