【问题标题】:My program was "Killed"我的程序被“杀死”
【发布时间】:2015-06-27 03:36:08
【问题描述】:

可能由内核在此question 中建议。我想看看我为什么被杀,就像暗杀发生的功能一样。 :)

另外,有什么办法可以让我的程序正常执行吗?


编年史

我的程序正常执行。但是,我们遇到了一个大数据集,1.000.000 x 960 浮点数,而我在家里的笔记本电脑无法承受(给了std::bad_alloc())。

现在,我在实验室中,使用 9.8 GiB 的台式机,处理器为 3.00GHz × 4,其内存是家用笔记本电脑的两倍多。

在家中,无法将数据集加载到存储数据的std::vector 中。在这里,在实验室中,这已完成,程序继续构建数据结构。

那是我最后一次听到它:

Start building...
Killed

实验室的桌面在 Debian 8 上运行。我的程序在数据集的子集上按预期运行,特别是 1.00.000 x 960 浮点数。


编辑

strace 输出终于可用了:

...
brk..
brk(0x352435000)                        = 0x352414000
mmap(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM (Cannot allocate memory)
mmap(NULL, 134217728, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0) = 0x7f09c1563000
munmap(0x7f09c1563000, 44683264)        = 0
munmap(0x7f09c8000000, 22425600)        = 0
mprotect(0x7f09c4000000, 135168, PROT_READ|PROT_WRITE) = 0
...
mprotect(0x7f09c6360000, 8003584, PROT_READ|PROT_WRITE) = 0
+++ killed by SIGKILL +++

所以这告诉我们我的记忆力不足,我

【问题讨论】:

  • 可能你分配了太多内存。
  • 这是可悲的事实@Skynet。我试图运行这个数据集好几天......
  • 看到你的问题我真的忍不住笑了:D
  • g++ -Wall -Wextra -g编译你的程序;然后使用调试器gdb & valgrind & strace;但是您的程序有错误。还有linux memory overcommit的STFW@
  • 程序被杀死而不是更优雅地失败的原因是overcommit。要在程序中获得干净的内存分配失败,请禁用过度使用(这不会使您的程序工作,只会帮助您了解正在发生的事情)。至于为什么过度使用会阻止有用的诊断,既然您知道“功能”的名称,您应该不会很难找到这些信息。

标签: c++ linux kernel debian kill


【解决方案1】:

在 C++ 中,浮点数是单个(32 位)浮点数: http://en.wikipedia.org/wiki/Single-precision_floating-point_format

这意味着您正在分配(无开销)3 840 000 000 bytes 数据。

或大约 3,57627869 GB..

让我们安全地假设向量的标头与数据相比什么都不是,并继续使用这个数字..

这是要构建的大量数据,Linux 可能会认为这只是内存泄漏,并通过杀死应用程序来保护它:

https://unix.stackexchange.com/questions/136291/will-linux-start-killing-my-processes-without-asking-me-if-memory-gets-short

我不认为这是一个过度使用的问题,因为您实际上在单个应用程序中使用了近一半的内存。

但也许.. 考虑这只是为了好玩.. 您正在构建一个 32 位应用程序吗? 如果它是 32 位版本,您将接近 2^32 (4Gb) 内存空间,您的程序可以寻址它..

因此,如果您分配了另一个大向量... bum bum bum

【讨论】:

  • bum³ 吓到我了。字节数是正确的。我家里的笔记本电脑是 32 位的。你觉得有什么联系吗? +1 的好答案。
  • 我不确定,但这是我的第一个怀疑。考虑首先在较小的数据集上测试您的程序(如一半大小),如果它运行,那么我将投入资金,应用程序无法分配必要的内存,并停止由内核包装其内存空间..
  • 我不确定你是否回答了我的 32 位问题。请参阅我对较小数据集的编辑。
  • std::vector,除非您保留正确的空间量,否则当您将项目推入其中时,每次需要增长时,其内存占用量都会增加一倍。例如,从 16 件到 32 件到 64 件到……所以它可能正试图远远超过您需要的大小。尝试使用“保留”来准确获取您的矢量需要多少项目。
  • 我现在很确定您根本无法分配所需的内存,可能的解释是您尝试分配的内存超出了 32 位应用程序所允许的内存。关于解决方案,好吧,LawfulEvil,知道他的东西,-您是否在分配之前为数据保留了空间?否则这就是你的解决方案! - 否则考虑,如果绝对有必要一次将整个数据集保存在内存中,或者如果可能的话加载一个子集,进行计算,卸载,加载下一个子集,等等......
【解决方案2】:

例如先安装信号处理器

static bool installSignalHandler(int sigNumber, void (*handler)(int) = signal_handler)
{
    struct sigaction action;
    memset(&action, 0, sizeof(action));
    action.sa_flags = SA_SIGINFO;
    action.sa_sigaction = signal_handler_action;
    return !sigaction(sigNumber, &action, NULL);
}

叫它:

installSignalHandler(SIGINT);
installSignalHandler(SIGTERM);

接下来的代码会被执行:

static void signal_handler_action(int sig, siginfo_t *siginfo, void* content) 
{
    switch(sig) {
        case SIGHUP:
            break;
        case SIGUSR1:
            break;
        case SIGTERM:
            break;
        case SIGINT:
            break;
        case SIGPIPE:
            return;
    }
}

查看siginfo_t 结构以获得所需的数据

printf("Continue. Signo: %d - code: %d - value: %d - errno: %d - pid: %ld - uid: %ld - addr %p - status %d - band %d",
                      siginfo->si_signo, siginfo->si_code, siginfo->si_value, siginfo->si_errno, siginfo->si_pid, siginfo->si_uid, siginfo->si_addr,
                      siginfo->si_status, siginfo->si_band);

【讨论】:

  • 不,这是错误的方法。顺便说一句,signal(7) 禁止从信号处理程序内部调用printf
  • 我添加了 printf,因为我无法将我使用的代码放入生产性 xD,请使用 syslog
  • printfsyslog 都不是 async-signal-safe-functions 所以两者都在信号处理程序中被禁止
  • 恐怕@BasileStarynkevitch 与我们在大学所做的相比是正确的。
  • 这些函数不被禁止但不推荐使用,因为它们会抛出一个新信号,你的代码会挂起或以未定义的方式运行。有时我们需要使用正确的词:-)。在任何情况下,您都可能内存不足,并且内核正在使用 sigkill/sigterm 杀死您的程序。您可以检查 dmesg 或使用strace运行程序
猜你喜欢
  • 1970-01-01
  • 2020-10-23
  • 1970-01-01
  • 1970-01-01
  • 2014-06-24
  • 2010-12-08
  • 2013-09-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多