我的Java代码实例捕获到NullPointerException,但是当我尝试登录StackTrace(基本上最终调用Throwable.printStackTrace())时,我得到的只是:

java.lang.NullPointerException


还有其他人遇到吗?我尝试谷歌搜索“ java空指针空堆栈跟踪”,但没有遇到这样的事情。

评论

上下文是什么?是否涉及多个线程?我在尝试获取SwingWorker中的异常的堆栈跟踪时遇到问题。

这里没有涉及线程,只是普通的旧Java。

@Bozho-不-尚不确定如何重现NullPointer。

相关:stackoverflow.com/questions/1076191/…

有关-XX的更多信息:-dmit中的-OmitStackTraceInFastThrow:stackoverflow.com/questions/4659151/…

#1 楼

您可能正在使用HotSpot JVM(最初由Sun Microsystems,后来由Oracle收购,是OpenJDK的一部分),它执行了很多优化。要获取堆栈跟踪,需要将选项-XX:-OmitStackTraceInFastThrow传递给JVM。优化是,当第一次发生异常(通常为NullPointerException)时,将打印完整的堆栈跟踪JVM会记住堆栈跟踪(或者可能只是代码的位置)。如果经常发生该异常,则不再打印堆栈跟踪,这既可以提高性能,又不会用相同的堆栈跟踪填充日志。

要了解如何在HotSpot JVM中实现此功能,获取它的副本并搜索全局变量OmitStackTraceInFastThrow。上一次我查看代码(在2019年)时,它在graphKit.cpp文件中。

评论


谢谢你的提示。知道是否有任何隐藏的陷阱可以传递此选项(只要我的应用程序不抛出大量异常,这似乎是无害的)?

–爱德华·斯特恩
2010-6-11 17:48

我知道没有隐藏的陷阱。查看Hotspot源代码时,您会看到此选项仅在一个地方使用(graphKit.cpp)。在我看来,这很好。

–罗兰·伊利格(Roland Illig)
2010年6月13日在11:14

以为我想补充一点信息,即优化堆栈跟踪时,是因为它至少已完全处理一次:jawspeak.com/2010/05/26/…

– sharakan
2012年6月19日14:56

我正在运行OpenJDK JVM版本1.8.0u171(Debian 9),它似乎也接受-XX:-OmitStackTraceInFastThrow标志。我尚未确认是否这就是为什么我也无法打印堆栈跟踪记录(例如,使用e.printStackTrace)的原因,但似乎很有可能。我扩展了答案以反映这一发现。

–克里斯·W(Chris W.)
18年6月5日在17:12

在我们的例子中,前125个异常具有堆栈跟踪,然后日志文件3次轮换中的其余异常都没有。这个答案对找到罪魁祸首很有帮助。

– Sukhmel
20 May 27 '10:03

#2 楼

正如您在评论中提到的,您正在使用log4j。我(无意间)发现了我写过的地方

LOG.error(exc);


,而不是典型的

LOG.error("Some informative message", e);

懒惰或者也许只是不考虑它。不幸的是,它的行为不符合您的预期。 logger API实际上将Object作为第一个参数而不是字符串-然后在该参数上调用toString()。因此,它没有打印出漂亮的堆栈跟踪,而是打印出了toString-在NPE的情况下,它几乎是无用的。

评论


+1:这可以解释所描述的行为,而您不是唯一发现此行为的人:)

– Peter Lang
2010年9月9日18:59

实际上,我们有一个标准策略,即从不使用上面的第一种形式(LOG.error(exc);)-我们始终使用2参数签名,以便我们向日志中添加一些描述性语句,而不仅仅是原始的堆栈跟踪。

–爱德华·斯特恩
2010年3月9日19:25

可以,但是策略并不意味着它总是可以正确执行!至少值得一提。

–史蒂文·斯兰斯克(Steven Schlansker)
2010年3月9日在20:12

是的,但是在这种情况下是;-)

–爱德华·斯特恩
2010年10月10日在16:59

#3 楼

过去我们已经看到了相同的行为。事实证明,由于某种疯狂的原因,如果多次在代码中的同一位置发生NullPointerException,则使用Log.error(String, Throwable)片刻后将停止包含完整的堆栈跟踪。

尝试进一步查看日志。您可能会找到罪魁祸首。

编辑:此bug听起来很相关,但很久以前已修复,可能不是原因。

评论


该错误已关闭,但仍需要-XX:-OmitStackTraceInFastThrow标志来解决性能优化问题。

–约书亚·戈德堡
2012年1月30日在22:09

我最近经常看到这种情况。关于什么可能导致此问题或如何解决的任何线索?日志记录系统可能已经运行了好几天,并且实际原因已经解决了,不要介意乏味的搜索...

– Pawel Veselov
2012年12月14日上午8:57

Pawel,您是否尝试过Joshua建议的-XX:-OmitStackTraceInFastThrow JVM标志?另请参阅stackoverflow.com/a/2070568/6198。

–马特·索尼特(Matt Solnit)
2012-12-14 23:38



这就是给我们的。谢谢。

– Slackwing
19年11月18日在19:24

#4 楼

这是一个解释:热点导致异常在生产中丢失了堆栈跟踪-修复程序

我已经在Mac OS X上对其进行了测试



java版本“ 1.6.0_26”
Java SE运行时环境(内部版本1.6.0_26-b03-383-11A511)

Java HotSpot(TM)64位服务器VM(内部版本20.1- b02-383,混合模式)对于此特定的代码片段,12288次迭代(+频率?)似乎是JVM的极限。决定使用预分配的异常...

#5 楼

exception.toString没有提供StackTrace,它仅返回此throwable的简短描述。
结果是以下内容的串联:

* the name of the class of this object
* ": " (a colon and a space)
* the result of invoking this object's getLocalizedMessage() method




使用exception.printStackTrace代替输出StackTrace。

评论


抱歉,我在原始帖子中打错了口号。我通过Log4J记录了这些信息,后者确实使用了printStackTrace()。

–爱德华·斯特恩
2010年3月9日在18:34

您是否尝试过使用getStackTrace()来确保记录器没有问题?

– Peter Lang
10 Mar 9 '10 at 18:37



如果您使用的是log4j,请确保将异常作为参数的一部分发送到log方法。我将发布答案。

–拉维·瓦劳(Ravi Wallau)
2010-3-9在18:53

@raviaw有效点! @爱德华·史特恩(Edward Shtern):您可以确认您确实使用log4j方法的2-arg形式吗?我知道您在下一个答案中提到这样做是公司政策,但是您绝对确定在这种情况下您会遵守该政策吗?

– KarstenF
2010-3-9在23:44

可能需要花费很长时间,但是异常是否可能源于某些第三方代码?也许它是一个(写得不好)的异常包装器,其toString()仅返回已包装的异常的类名,并且无法提供基础的堆栈跟踪。尝试将logger.info(“ Exception class =” + exc.class.getCanonicalName())之类的内容放入catch块中,然后看得到什么。

– KarstenF
2010年10月10日19:16

#6 楼

替代建议-如果您使用的是Eclipse,则可以在NullPointerException本身上设置一个断点(在Debug透视图中,转到“ Breakpoints”选项卡,然后单击其中带有!的小图标)。

同时选中“ caught”和“ uncaught”选项-现在,当您触发NPE时,您将立即断点,然后逐步执行,看看它是如何处理的以及为什么没有得到堆栈跟踪。

#7 楼

toString()仅返回异常名称和可选消息。我建议致电

exception.printStackTrace()


转储邮件,或者如果您需要详细信息:

 StackTraceElement[] trace = exception.getStackTrace()


评论


参见上文-我打错了-我正在使用printStackTrace()。

–爱德华·斯特恩
2010年3月9日在18:34

#8 楼

(关于您的代码是调用printStackTrace()还是由日志记录处理程序完成,您的问题尚不清楚。)

以下是关于可能发生的情况的一些可能的解释:


正在使用的记录器/处理程序已配置为仅输出异常的消息字符串,而不是完整的堆栈跟踪。
您的应用程序(或某些第三方库)正在使用LOG.error(ex);而不是q记录异常(例如)log4j Logger方法的2参数形式。
消息来自与您认为不同的地方;例如它实际上是某种第三方库方法,或者是较早的调试尝试遗留下来的一些随机信息。
正在记录的异常已使某些方法过载,从而使堆栈跟踪变得晦涩。如果真是这样,则该异常将不是真正的NullPointerException,而是某些NPE的自定义子类型,甚至是一些未连接的异常。

我认为最后一种可能的解释是不太可能的,但是人们至少会考虑做这种事情以“防止”逆向工程。当然,只有诚实的开发人员才能真正成功地使生活变得困难。

#9 楼

当您在项目中使用AspectJ时,可能会发生某些方面隐藏其堆栈跟踪的部分的情况。例如,今天我有:在IntelliJ中运行测试时,打印了另一个堆栈跟踪:

java.lang.NullPointerException:
  at com.company.product.MyTest.test(MyTest.java:37)


#10 楼

这将输出异常,仅用于调试您应该更好地处理异常。

import java.io.PrintWriter;
import java.io.StringWriter;
    public static String getStackTrace(Throwable t)
    {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw, true);
        t.printStackTrace(pw);
        pw.flush();
        sw.flush();
        return sw.toString();
    }