我已经有我们的Java代码的实例捕捉一个NullPointerException,但当我试图记录StackTrace(基本上最终调用Throwable.printStackTrace()),我得到的是:

java.lang.NullPointerException

有人遇到过吗?我试着在谷歌上搜索“java空指针空堆栈跟踪”,但没有遇到这样的东西。


当前回答

VM停止输出多次抛出的异常的堆栈跟踪。这是发生在C2编译中的优化之一。

根据OpenJDK源代码,此优化应用于以下例外情况:

nullpointerexception -ArithmeticException -ArrayIndexOutOfBoundsException -ArrayStoreException classcastexception

其他回答

当您在项目中使用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)

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

-XX:-OmitStackTraceInFastThrow

优化的方法是,当异常(通常是NullPointerException)第一次发生时,打印完整的堆栈跟踪,JVM记住堆栈跟踪(或者可能只是代码的位置)。当异常发生的次数足够频繁时,堆栈跟踪就不再打印了,这既是为了获得更好的性能,也是为了不让相同的堆栈跟踪充斥日志。

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

例外。toString不给你StackTrace,它只返回

这是一个简短的描述扔。 结果是: *该对象的类名 * ": "(冒号加空格) *调用该对象的getLocalizedMessage()方法的结果


使用异常。而不是printStackTrace来输出StackTrace。

(您的问题仍然不清楚您的代码是否调用printStackTrace()或这是由日志处理程序完成的。)

以下是一些可能的解释:

The logger / handler being used has been configured to only output the exception's message string, not a full stack trace. Your application (or some third-party library) is logging the exception using LOG.error(ex); rather than the 2-argument form of (for example) the log4j Logger method. The message is coming from somewhere different to where you think it is; e.g. it is actually coming some third-party library method, or some random stuff left over from earlier attempts to debug. The exception that is being logged has overloaded some methods to obscure the stacktrace. If that is the case, the exception won't be a genuine NullPointerException, but will be some custom subtype of NPE or even some unconnected exception.

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

下面是一个解释:Hotspot导致异常在生产中丢失堆栈跟踪-以及修复

我在Mac OS X上进行了测试

Java版本“1.6.0_26” Java(TM) SE运行时环境(build 1.6.0_26-b03-383-11A511) Java HotSpot(TM) 64位服务器虚拟机(build 20.1-b02-383,混合模式) 对象字符串= "abcd"; Int I = 0; While (i < 12289) { 我+ +; 尝试{ 整数a =(整数)字符串; } catch(异常e) { e.printStackTrace (); } }

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