【发布时间】:2016-04-13 07:10:54
【问题描述】:
我有一个典型的 Heisenbug 示例,它是由我以前从未见过的条件触发的。我的旧应用程序(大约 100K sloc 的旧代码)在特定实例中无法正常工作,仅启用 JPDA 远程调试就足以改变行为,导致应用程序正常工作:除了添加“-Xdebug -Xnoagent -Xrunjdwp:什么都不做: transport=dt_socket,server=y,suspend=n,address=6666" 到虚拟机的命令行隐藏错误(有或没有实际连接)。鉴于我有一个完全可重复的测试用例,我讨厌通过代码更改来扰乱它,以防它再次隐藏起来。当然,这仅在生产中发生。
通常,我会立即假设存在线程问题,但是 a) 行为是 100% 失败与 100% 正常工作,并且 b) 在相关代码路径中没有明确使用线程。然后我们的团队试图列出导致这种行为的其他原因,所以我认为 Stack Overflow 的团队思维可能会增加一些。
Java 中的 Heisenbugs:
- 线程:错误的同步、竞争条件、隐式排序假设。
- 显式调试/记录代码:更改代码路径会导致/防止问题。不太常见的是,日志级别的更改可能会导致时间更改(再次线程化)和 I/O 资源使用的差异。
- 本机代码库可以拖入非 java Heisenbug 问题。
- 期待终结器以可预测的方式运行。
- 关于弱引用的错误假设。
- 假设固定大小的缓存永远不会填满。
- 期望哈希码的唯一性。
- 假设 == 适用于字符串(或不适用于在某些情况下可能被实习的字符串)。
- VM 错误(不,从未 发生过;)。
- 测试方法错误。尤其是当存在依赖于测试成功的隐藏变量时。 (这看起来是我们的实际问题。一个测试成功导致客户运行下一个测试,由于策略问题而失败。失败导致根据策略在调试模式下运行,这导致成功。叹息)
还有其他值得探讨的案例吗?
编辑:
- 是的,JPDA 启用代码使用旧语法。我还没有测试过使用现代语法是否也会改变行为。
- 这台特定机器使用 1.8.0_45-b14 作为 JRE 和 HotSpot 64 位服务器 VM(内部版本 25.45-b02)
- 虽然这个问题是一般性的,但煽动性的问题是真实的和当前的。由于问题出现在已部署的系统中,我在想要让它与 -Xdebug 作为解决方法一起运行以使其保持运行和想要追踪底层错误并杀死它之间左右为难。
- 有问题的故障程序是多步骤数据处理管道的一部分 - 细节无关紧要,但最好将其理解为一个独立的应用程序,它从数据库中获取一些信息,然后使用它来修改一些文件.系统中出现问题的部分似乎是来自数据库的信息没有被正确解释——来自损坏的对象 ORM 或缓存的任何内容。当它“损坏”时,确定它是否有工作要做的应用程序逻辑(基于数据库的内容)对所有迭代(包括程序的多次调用在内的数千次迭代)做出错误的选择。当它“工作”时(唯一的区别是 vm 是否使用 -Xdebug 运行),应用程序会为所有迭代做出正确的选择。在这个配置中是完全一致的。针对不同数据库运行的相同代码不会失败。有一些证据(在我参与此代码之前)表明,过去曾出现过类似的行为,在看似微小的代码更改后神秘地开始工作......请参阅“Heisenbug”
【问题讨论】:
-
如果可能的话,我会一分为二。特别是调试让我怀疑 JIT。
-
这个问题可以为我们许多人提供一些有趣的信息。为什么有人要关闭它?
-
@m.thome,您介意更准确地解释一下“行为是 100% 失败与 100% 正常”的意思吗?我的意思是,100% 的时间失败或 100% 的时间通过的行为到底是什么?另外,您的应用程序是什么(例如桌面、Web 服务、独立的单线程命令行应用程序等)?我不是在寻找机密的商业信息,但更多的上下文将帮助我缩小答案中一些可能的确凿证据。
-
另外,您使用的是哪个 Java 版本?
-
回到老派的调试我猜...在发布模式下记录状态?我的意思是,你还能做什么?这是我想任何人都可以给出的最佳答案。总帐。