Java 中没有 StackTrace 的 NullPointerException

NullPointerException in Java with no StackTrace

提问人:Edward Shtern 提问时间:3/10/2010 最后编辑:ДМИТРИЙ МАЛИКОВEdward Shtern 更新时间:9/14/2023 访问量:155738

问:

我已经让我们的 Java 代码实例捕获了一个 ,但是当我尝试记录 StackTrace(基本上最终调用 ),我得到的只是:NullPointerExceptionThrowable.printStackTrace()

java.lang.NullPointerException

还有其他人遇到过吗?我尝试在谷歌上搜索“java null pointer empty stack trace”,但没有遇到这样的事情。

Java NullPointerException

评论

0赞 Michael Myers 3/10/2010
背景是什么?是否涉及多个线程?我在尝试获取 SwingWorker 中异常的堆栈跟踪时遇到了问题。
0赞 Edward Shtern 3/10/2010
这里不涉及线程,只是普通的旧 Java。
1赞 Edward Shtern 3/11/2010
@Bozho - 不 - 还不确定如何重现 NullPointer。
1赞 Joshua Goldberg 1/31/2012
相关新闻: stackoverflow.com/questions/1076191/...
0赞 Vadzim 12/8/2017
有关 dup 的更多信息:stackoverflow.com/questions/4659151/...-XX:-OmitStackTraceInFastThrow

答:

11赞 Peter Lang 3/10/2010 #1

exception.toString 不会给你 StackTrace,它只返回

这个投掷物的简短描述。 结果是以下项的串联:

* 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

评论

1赞 Edward Shtern 3/10/2010
对不起,我在原来的帖子中说错了。我通过 Log4J 记录这些内容,它确实使用 printStackTrace()。
1赞 Peter Lang 3/10/2010
您是否尝试过使用以确保问题不出在您的记录器上?getStackTrace()
1赞 Ravi Wallau 3/10/2010
如果您使用的是 log4j,请确保将异常作为参数的一部分发送到 log 方法。我会发布一个答案。
0赞 KarstenF 3/10/2010
@raviaw有效的观点!@Edward Shtern:您能确认您确实使用了 log4j 方法的 2-arg 形式吗?我知道您在后面的回答中提到这是公司的政策,但您绝对确定在这种情况下您遵守了该政策吗?
0赞 KarstenF 3/11/2010
这可能是一个很长的机会,但异常是否可能起源于某些第三方代码?也许它是一个(写得不好的)异常包装器,其 toString() 仅返回包装异常的类名,并且无法提供底层堆栈跟踪。尝试将类似 logger.info(“Exception class = ” “ + exc.class.getCanonicalName()) 之类的东西放入你的 catch 块中,看看你得到了什么。
2赞 Sheldon Young 3/10/2010 #2

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

exception.printStackTrace()

转储消息,或者如果您需要血腥的详细信息:

 StackTraceElement[] trace = exception.getStackTrace()

评论

0赞 Edward Shtern 3/10/2010
见上文 - 我说错了 - 我正在使用 printStackTrace()。
1赞 Michael D. Irizarry 3/10/2010 #3

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

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();
    }
69赞 Steven Schlansker 3/10/2010 #4

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

LOG.error(exc);

而不是典型的

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

通过懒惰,或者只是不去想它。不幸的是,它的行为并不像您预期的那样。记录器 API 实际上将 Object 作为第一个参数,而不是字符串 - 然后它对参数调用 toString()。因此,它没有得到漂亮的堆栈跟踪,而只是打印出 toString - 这在 NPE 的情况下是相当无用的。

也许这就是你正在经历的?

评论

0赞 Peter Lang 3/10/2010
+1:这可以解释所描述的行为,而且你不是唯一一个发现这种:)的人
4赞 Edward Shtern 3/10/2010
我们实际上有一个标准策略,即从不使用上面的第一种形式 (LOG.error(exc);) - 我们始终使用 2 参数签名,以便我们在日志中添加一些描述性语句,而不仅仅是原始堆栈跟踪。
6赞 Steven Schlansker 3/10/2010
当然,但政策并不意味着它总是正确执行!至少我认为值得一提。
0赞 Edward Shtern 3/11/2010
没错,但在这种情况下是;-)
5赞 Steven Schlansker 3/10/2010 #5

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

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

1赞 Stephen C 3/10/2010 #6

(你的问题仍然不清楚你的代码是调用还是由日志记录处理程序完成。printStackTrace()

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

  • 正在使用的记录器/处理程序已配置为仅输出异常的消息字符串,而不是完整的堆栈跟踪。

  • 您的应用程序(或某些第三方库)使用 log4j Logger 方法(例如)而不是 2 参数形式来记录异常。LOG.error(ex);

  • 信息来自与你想象的不同的地方;例如,它实际上来自一些第三方库方法,或者是早期尝试调试时遗留下来的一些随机内容。

  • 记录的异常使某些方法过载,使堆栈跟踪变得模糊不清。如果是这种情况,则异常将不是真正的 NullPointerException,而是 NPE 的某个自定义子类型,甚至是某个未连接的异常。

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

36赞 Matt Solnit 3/10/2010 #7

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

请尝试在日志中进一步查看。你可能会找到罪魁祸首。

编辑:这个错误听起来很相关,但它很久以前就被修复了,它可能不是原因。

评论

3赞 Joshua Goldberg 1/31/2012
该 bug 已关闭,但仍需要 -XX:-OmitStackTraceInFastThrow 标志来解决性能优化问题。
0赞 Pawel Veselov 12/14/2012
我最近经常看到这种情况。关于可能导致此问题的原因或如何解决它的任何线索?日志记录系统可能已经运行了好几天,实际原因轮换出来了,更不用说繁琐的搜索了......
5赞 Matt Solnit 12/15/2012
Pawel,你试过 Joshua 建议的 JVM 标志吗?另请参见 stackoverflow.com/a/2070568/6198-XX:-OmitStackTraceInFastThrow
1赞 Andrew Cheong 11/19/2019
这就是我们。谢谢。
565赞 Roland Illig 6/10/2010 #8

您可能正在使用 HotSpot JVM(最初由 Sun Microsystems 开发,后来被 Oracle 收购,是 OpenJDK 的一部分),它执行了大量优化。要获取堆栈跟踪,您需要将以下选项传递给 JVM:

-XX:-OmitStackTraceInFastThrow

优化是,当第一次发生异常(通常为 )时,将打印完整的堆栈跟踪,并且 JVM 会记住堆栈跟踪(或者可能只是代码的位置)。当该异常发生得足够频繁时,将不再打印堆栈跟踪,这样既可以实现更好的性能,也可以避免使用相同的堆栈跟踪淹没日志。NullPointerException

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

评论

1赞 Edward Shtern 6/12/2010
谢谢你的提示。知道传递此选项是否有任何隐藏的陷阱(只要我的应用程序不抛出大量异常,它似乎非常无害)?
0赞 Roland Illig 6/13/2010
据我所知,没有隐藏的陷阱。当您查看热点源代码时,您可以看到此选项仅在一个地方使用(graphKit.cpp)。这在我看来很好。
37赞 sharakan 6/19/2012
我以为我会添加一些额外的信息,即当堆栈跟踪被优化时,这是因为它至少被完全处理过一次:jawspeak.com/2010/05/26/......
1赞 Chris W. 6/6/2018
我正在运行OpenJDK JVM,版本1.8.0u171(Debian 9),它似乎也接受该标志。我尚未确认这是否是我也无法打印堆栈跟踪的原因(例如,使用 ),但似乎很有可能。我扩展了答案以反映这一发现。-XX:-OmitStackTraceInFastThrowe.printStackTrace
0赞 sukhmel 5/27/2020
在我们的示例中,前 125 个异常具有堆栈跟踪,然后日志文件的 3 次轮换中的其余异常没有堆栈跟踪。这个答案对找到罪魁祸首非常有帮助。
24赞 Benoît Guérout 10/15/2011 #9

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

我已经在Mac OS X上测试过了

  • Java 版本“1.6.0_26”
  • Java(TM) SE 运行时环境(内部版本 1.6.0_26-b03-383-11A511)
  • Java HotSpot(TM) 64 位服务器 VM(内部版本 20.1-b02-383,混合模式)

    Object string = "abcd";
    int i = 0;
    while (i < 12289) {
        i++;
        try {
            Integer a = (Integer) string;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

对于这个特定的代码片段,12288 次迭代(+频率?)似乎是 JVM 决定使用预分配异常的限制......

评论

1赞 Roland Illig 6/7/2017 #10

当您在项目中使用 AspectJ 时,可能会发生某些方面隐藏其堆栈跟踪部分的情况。例如,今天我有:

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

此堆栈跟踪是在通过 Maven 的 surefire 运行测试时打印的。

另一方面,在 IntelliJ 中运行测试时,打印了不同的堆栈跟踪:

java.lang.NullPointerException
  at com.company.product.library.ArgumentChecker.nonNull(ArgumentChecker.java:67)
  at ...
  at com.company.product.aspects.CheckArgumentsAspect.wrap(CheckArgumentsAspect.java:82)
  at ...
  at com.company.product.MyTest.test(MyTest.java:37)
2赞 S4RUUL 8/23/2022 #11

虚拟机停止输出已引发几次的异常的堆栈跟踪。这是 C2 编译中发生的优化之一。

根据 OpenJDK 的源代码,此优化适用于以下异常:

-NullPointerException -算术异常 -ArrayIndexOutOfBoundsException -ArrayStoreException -ClassCastException

0赞 DMC19 9/14/2023 #12

我已经解决了在for循环中打印stackTrace的问题。

for (StackTraceElement st : e.getStackTrace()) {
   LOGGER.error(st.toString());
}

这样,它就会打印整个 stackTrace。使用其他方法,我无法获得更多信息。