【发布时间】:2010-09-10 01:32:39
【问题描述】:
我正在编写一个跨计算集群运行的 C 应用程序(使用 condor)。我尝试了很多方法来揭示有问题的代码,但都无济于事。
线索:
- 平均而言,当我在 15 台机器上运行代码 2 天时,会出现两到三个段错误(信号 11)。
- 当我在本地运行代码时,我没有遇到段错误。我在家用机器上运行了将近 3 周。
尝试:
- 我在 valGrind 中在本地运行了四天的代码,没有出现内存错误。
- 我通过定义自己的信号处理程序捕获了段错误信号,以便可以输出一些程序状态。
- 现在,当发生段错误时,我可以使用回溯打印出当前堆栈。
- 我可以打印出变量值。
- 我创建了一个设置为当前行号的变量。
- 还尝试注释掉代码块,希望如果问题消失,我会发现段错误。
遗憾的是,输出的行号是相当随机的。我不完全确定我可以用堆栈跟踪做什么。我假设它只记录发生段错误的函数的地址是否正确?
怀疑:
- 我怀疑 condor 用于跨机器移动作业的检查点系统对内存损坏更敏感,这就是我在本地看不到它的原因。
- 索引已被错误破坏,并且这些索引导致了段错误。这可以解释段错误发生在相当随机的行号上的事实。
更新
对此进行了更多研究,我发现了以下链接:
LibSegFault - 用于自动捕获和打印有关段错误的状态数据的库。
Stack unwinding (stack trace) with GCC 教程关于捕获段错误并获取违规指令的行号。
更新 2
Greg 建议查看 condor 日志并“将段错误与 condor 从检查点重新启动可执行文件的时间相关联”。查看日志,所有段错误都在重新启动后立即发生。当作业从一种类型的机器切换到另一种类型时,所有故障似乎都会发生。
更新 3
段错误是由主机之间的差异引起的,通过将 condor 提交文件中的“requiremets”字段设置为问题完全消失。
可以单独设置机器:
requirements = machine == "hostname1" || machine == "hostname2"
或一整类机器:
requirements = classOfMachinesName
查看需求示例here
【问题讨论】:
-
最近的 gcc 有挡泥板选项来做一些运行时检查。
-
这似乎更像是一个多进程践踏问题而不是内存损坏问题(尤其是因为您无法在家中重现它)
-
@Mark ,我认为操作系统会阻止这种情况?不要进程有不同的地址空间。
-
@e5,我想我的意思是线程,我不完全了解环境,但症状类似于我之前看到的由某些比赛/计时条件导致的问题——持续失败但不断变化职位
-
@E5,好吧,该死。有很多简单的方法可以获得不可重现的崩溃。另一方面,调试单线程代码要容易得多。我怀疑你实际上可以对你的集群使用 gdb 的提示将是最有效的。
标签: c memory-corruption condor