如何调试 Java 应用程序中的静默故障?

Posted

技术标签:

【中文标题】如何调试 Java 应用程序中的静默故障?【英文标题】:How do I debug silent failures in Java applications? 【发布时间】:2010-11-05 11:02:03 【问题描述】:

我正在尝试调试我的 Java 应用程序中的一个问题,该问题不会引发错误、没有异常,甚至不会使应用程序崩溃(似乎故障发生在单独的线程中)。

问题似乎出在对库函数的调用中(如果重要的话,它是JAXBContext.newInstance(String))。程序将到达调用之前的那一行,但不会到达它之后的那一行。我的catch 块没有输入,程序继续运行。

在尝试为通过 Struts 传入的 Web 请求呈现 XML 响应时会出现问题。请求已被处理,代码应编组响应对象。客户端立即得到响应(因此代码似乎没有陷入循环),但它只是空的。

我在有问题的行之前设置了一个断点,但调试器只是在它上面运行,我不知道为什么。

我正在使用 Eclipse,应用程序在以 -Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=y 启动的 OSGi 容器 (Apache Felix) 中运行。然后我在 Eclipse 中使用“远程 Java 应用程序”的调试设置来连接调试器。

有什么技巧可以解决这样的问题?

【问题讨论】:

您确定 IDE 指向的是与服务器上的二进制文件相同的源代码吗? 是的,这一切都在我的本地机器上,OSGi 容器直接从我的 IDE 的输出目录运行代码。 我不熟悉 OSGi 容器,它是否像 JBoss 一样将部署的二进制文件移动到另一个目录?我会尝试更改您的代码、System.out.println 或类似的东西,然后确保它被执行以确认这一点。我通常发现调试器跳过代码行表明 IDE 和服务器彼此不同步。 是的,这听起来很合理,但我不知道它们应该如何不同步。源代码只有一份副本,运行的二进制文件是 IDE 生成的。 如果这是问题所在,那么您认为正在运行的二进制文件并不是实际运行的。服务器将存档文件解压缩到另一个目录是很常见的。使用 JBoss,这是非常可靠的,但在您不断部署的开发环境中,我已经看到热部署停止工作 - JBoss 停止解压缩新的存档文件,服务器继续在旧的二进制文件上运行。我想你在这里可能会遇到类似的问题。在 JBoss 上,您可以通过删除存档文件、弹回服务器然后重新部署来解决它。不确定 OSGI,但我会尝试。 【参考方案1】:

可能是一个显而易见的问题,但你确定你正在捕捉 Throwable 吗?未经检查的异常很容易导致有问题的线程死掉(假设调用堆栈中没有任何人在你上面。)

由于您使用调试参数在启动时挂起 VM,因此我假设您已确认调试器已正确附加。您说调试器跳过调用的事实非常可疑。你能在这个应用程序中打断点吗?在这堂课上呢?在这个线程中呢?

在没有调试器的情况下,您是如何缩小问题范围的? println/调试到一个文件?

你能粘贴一个有问题的方法的代码sn-p吗?

您可以通过在问题发生之前创建第二个线程并将其连接到您认为正在死亡的线程来确认线程正在死亡的理论。然后当相关线程退出时,将调用第二个线程的 run() 方法,并且您会知道它死了(但仍然不知道为什么。)

在回答您的一般问题时,当我在 Java 应用程序中遇到无法在调试器中重现的错误(由于各种原因不时发生)时,我会使用 sysout printlns 或输出逐步修改我的代码到文件。如有必要,我还可以修改我的代码正在调用的代码。如果您没有正在调用的代码的源代码,您可以尝试使用众多 BCI 框架之一将您的字节码注入到相关方法中。这是一个乏味的过程,但只是偶尔发生。

【讨论】:

+1 并非所有 Throwable 都是 Exceptions,我们通常会捕获 Exceptions;这很容易从我们身边溜走。【参考方案2】:

您可以尝试获取Thread Dump - 它会告诉您是否有任何方法被阻塞(例如等待输入)。 [编辑:重新阅读您的原始问题,获取线程转储可能无济于事,因为看起来实际上没有任何阻塞。但我将它留在这里,因为我发现它在许多其他情况下很有用!]

如果您认为错误发生在另一个线程中,您还可以设置UncaughtExceptionHandler 来尝试捕获它。

【讨论】:

阻塞:不,这次不行。 UncaughtExceptionHandler 是个好主意,不幸的是,它也没有捕获任何东西。【参考方案3】:

如果您确定问题出在该方法的某个地方,您可以尝试查看JAXB source code。

编辑:

好吧,如果它变得非常糟糕,您可以使用调试工具构建自己的私有副本。我希望你不必诉诸于此。

【讨论】:

好吧,我会试一试,但如果没有调试器介入,我可能会遇到困难。【参考方案4】:

也许在调用内部发生了一个无限循环,这就是为什么你没有进一步了解的原因 - 但这可能不会导致崩溃(除非在每个循环中都使用内存)。

【讨论】:

不,我不这么认为。该错误发生在处理通过 Struts 传入的 Web 请求并且客户端立即得到结果(为空)时。所以应用程序不会挂起,它会跳出处理过程。

以上是关于如何调试 Java 应用程序中的静默故障?的主要内容,如果未能解决你的问题,请参考以下文章

如何调试静默崩溃?多处理 python

DOM事件处理程序的异常管理器-不再出现静默故障

如何使用eclipse中的debug工具,调试部署在weblogic中的应用?

静默错误:Oracle 数据库是如何应对和处理的 ?

多线程 python 脚本静默死亡 - 如何调试

如何在 C 中调试 gdb 中的 St9bad_alloc 故障?