【问题标题】:Java equivalent of coredump on uncaught exceptionJava 等效于未捕获异常的 coredump
【发布时间】:2012-12-16 22:13:10
【问题描述】:

Linux coredump 或 Windows minidump 的 Java 等价物是什么?我读过关于堆转储的内容,它看起来像我想要的,但是如何在未捕获的异常上(自动)触发它们?

我知道未捕获的异常处理程序,并且我已经在使用它来打印异常 + 堆栈跟踪并终止整个应用程序(否则线程死亡并且应用程序继续运行?嗯?)我还发现 this post 关于如何从代码中记录堆转储,但如果我从未处理的异常处理程序中执行此操作,Java 已经捕获了异常并且堆栈跟踪(和参数)已经消失。

我遇到了 -XX:+HeapDumpOnOutOfMemoryError 标志,它似乎可以满足我的需要,不幸的是,它仅适用于内存不足的异常,而不适用于其他未捕获的异常。

到目前为止,这是我能够从 google 中获得的唯一内容。目前我正在使用带有异常断点的附加调试器,但这是不切实际的,因为它也会在处理的异常上中断,因此不能在无人监督的情况下使用。

[动机更新]

我希望能够检查堆栈跟踪的参数和局部变量,以找出导致异常的原因。它通常是空引用异常或失败的断言,我不能总是从行号猜测到底出了什么问题。在 C/C++ 中,我习惯于使用 coredump/minidump 崩溃,然后进一步检查实际导致崩溃的原因。

【问题讨论】:

    标签: java error-handling crash-dumps


    【解决方案1】:

    如果您不使用 JNI 并调用本机代码,则很难破坏 JVM 的内存,异常不需要堆转储或核心转储。

    在 Java 世界中,抛出异常的代码应该为阅读异常的人提供足够的信息,以便能够确定问题的原因。有时这不会发生,处理它的正确方法是修改异常抛出代码以在异常中提供更多信息或将某些内容记录到日志文件中。

    如果抛出异常的代码不受您的控制并且您无权访问源代码,那么您可以使用 AspectJ 来编织一些关于该方法抛出异常的建议,然后您可以检查该函数方面的参数并记录它们。但是在您进行路由 aspectJ / 字节码编织之前,您可能想查看您尝试理解的代码是否使用 log4j 或其他具有调试日志记录级别的日志框架,这可能会包含您正在寻找的信息。

    您可能想看看 Google Guava Open Source Library,它有一个很好的关于 Pre conidtions 的部分,您可以使用它来验证参数并获取有关问题原因的更多上下文。 http://code.google.com/p/guava-libraries/wiki/PreconditionsExplained

    您还想查看http://www.slf4j.org/,它有一个很好的日志记录 API,您可以使用它来记录有关您遇到的问题的信息。

    你也可以在eclipse中做条件断点,这允许你让断点只在特定情况下执行。 http://wiki.eclipse.org/FAQ_How_do_I_set_a_conditional_breakpoint%3F

    另一个可以使用的工具是 jvisiual vm,它允许你连接到一个活动的 vm 并找出很多关于 vm 内部发生的事情的信息,比如所有线程在哪里,如果有的话是死锁,GC 正在做什么,您可以使用它触发堆转储,然后查询它们并查看堆转储中特定对象的状态。 http://docs.oracle.com/javase/7/docs/technotes/guides/visualvm/index.html

    【讨论】:

    • 这是一个游戏服务器应用程序,但独立运行,没有嵌入 apache 或其他框架。大部分来源都在我的控制之下。
    • 感谢您的建议。总而言之,从其他帖子中,我认为没有真正等同于 coredumps/mindumps,我需要寻找替代方案。
    • 不需要小型转储?对于 any 远程复杂系统,这是错误的,以下建议毫无用处。您需要检查许多对象的微小内部状态,这些对象在发生某些事情时甚至可能彼此不知道;这不能合理地包含在异常或日志语句中。将实时附加到生产系统不太可能,只有当问题很容易在单个服务器上重现时...... minidump 是唯一的方法。或者如果 Java 不是一个笑话,它会是这样
    【解决方案2】:

    我不认为堆转储是您正在寻找的。它只是堆的转储,打开该开关的原因是,如果您遇到 OOM 异常,您可能想要调查的一件事是内存的用途,以便您可以找到泄漏(或其他问题)。

    这正是您想要使用它们的目的吗?也许有一种替代但更好的方法来满足您在 java 中的需求。我认为我从来没有需要像 java 的核心或小型转储之类的东西。除了我希望有一种方法可以调用 abort() 只是为了能够研究代码是如何结束的。

    【讨论】:

    • 我想检查堆栈跟踪的参数以及可能从它们访问的对象。单独的堆栈跟踪只是告诉我发生了什么错误,而不是导致它的原因。
    • 堆转储对您毫无帮助。我建议要么更改代码以引发正确的异常,要么(如果它是第三方库)更改为按预期工作的东西。如果不是在客户现场进行事后调试,而是在开发阶段,任何调试器都应该足够了。有关更详细的说明,请参阅@ams 答案。
    • 好吧,但我想做“事后调试”,它是一个游戏服务器应用程序,有很多交互正在进行,所以用附加调试器。不过感谢关键字,也许我可以在事后调试下找到一些东西。
    • 如果您可以控制服务器。也许您可以编写一个 UncaughtExceptionHandler 在终止之前存储尽可能多的有关当前状态的信息?我用谷歌搜索的第一个链接是 javapractices.com/topic/TopicAction.do?Id=229 ,它可能已经过时了,但可以作为一个起点。
    • 好吧,就像我已经写的那样,在未捕获的异常处理程序中,堆栈已经被展开,所以“尽可能多的信息”只是堆栈跟踪,缺少最重要的东西,来自的参数失败的功能。在我的场景中,可通过静态变量访问的对象不包含任何有趣的信息。
    【解决方案3】:

    Oracle 的这篇博客描述了如何以编程方式进行堆转储:

    https://blogs.oracle.com/sundararajan/entry/programmatically_dumping_heap_from_java

    它本质上使用 Hotspot 的 com.sun.management.HotSpotDiagnosticMXBean 及其 dumpHeap() 方法。它可能只适用于 Oracle/Sun JVM,并且不能保证它会在遥远的将来运行。

    然而,困难的部分是一旦你有了这个堆转储,如何从中获取有用的信息。我想你会从找到新抛出的异常对象开始,然后从那里开始。堆转储不会帮助您处理方法参数和局部变量值,因为堆转储中不会出现原语和引用。

    【讨论】:

    • 我原来的帖子中有那个链接,所以我知道,但是当未处理的异常处理程序运行时,堆栈跟踪已经消失了。也许堆转储确实是解决此问题的错误方法,但看起来它接近核心转储。
    猜你喜欢
    • 2010-11-25
    • 2012-10-26
    • 2015-07-04
    • 1970-01-01
    • 1970-01-01
    • 2014-03-22
    • 2010-09-28
    • 2012-05-31
    相关资源
    最近更新 更多