我们的Java代码遇到了NullPointerException
的情况,但是当我尝试记录StackTrace(实际上调用了Throwable.printStackTrace()
)时,我得到的仅仅是:
java.lang.NullPointerException
有其他人遇到过这个问题吗?我尝试谷歌搜索“java空指针空栈跟踪”,但没有找到类似的内容。
我们的Java代码遇到了NullPointerException
的情况,但是当我尝试记录StackTrace(实际上调用了Throwable.printStackTrace()
)时,我得到的仅仅是:
java.lang.NullPointerException
有其他人遇到过这个问题吗?我尝试谷歌搜索“java空指针空栈跟踪”,但没有找到类似的内容。
你可能正在使用HotSpot JVM(最初由Sun Microsystems开发,后被Oracle收购,是OpenJDK的一部分),其进行了大量的优化。要获取堆栈跟踪信息,您需要向JVM传递以下选项:
-XX:-OmitStackTraceInFastThrow
优化在于,当第一次发生异常(通常是 NullPointerException
)时,将打印完整的堆栈跟踪,并且JVM会记住堆栈跟踪(或者可能只是代码位置)。当该异常足够频繁地发生时,不再打印堆栈跟踪,以实现更好的性能和避免将相同的堆栈跟踪记录到日志中。要查看这在 Hotspot JVM 中是如何实现的,请 获取它的副本 并搜索全局变量 OmitStackTraceInFastThrow
。我上次看代码是在2019年,当时它在文件 graphKit.cpp 中。正如您在评论中提到的一样,您正在使用 log4j。我偶然发现了一个我写错的地方
LOG.error(exc);
不是典型的
LOG.error("Some informative message", e);
由于懒惰或者只是没有考虑到,代码行为表现与你的期望不同。实际上,logger API将第一个参数作为对象(Object)而不是字符串(string)处理,并调用该参数的toString()方法。因此,它并不会打印出漂亮的堆栈跟踪信息,而是直接打印出toString()返回的内容,这在NPE的情况下是相当无用的。
也许这就是你正在遇到的问题?
-XX:-OmitStackTraceInFastThrow
JVM 标志吗?请参考 https://dev59.com/P3NA5IYBdhLWcg3wI6R4#2070568。 - Matt Solnit以下是解释:Hotspot caused exceptions to lose their stack traces in production – and the fix
我已经在 Mac OS X 上进行了测试
Java HotSpot(TM) 64 位服务器虚拟机 (build 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 决定使用预分配异常的限制...exception.toString
无法提供StackTrace,它只返回异常信息本身。
a short description of this throwable. The result is the concatenation of:
* the name of the class of this object * ": " (a colon and a space) * the result of invoking this object's getLocalizedMessage() method
exception.printStackTrace
代替,以输出堆栈跟踪信息。getStackTrace()
来确保问题不是出在你的日志记录器上吗? - Peter Lang替代建议 - 如果您使用Eclipse,可以在NullPointerException本身上设置断点(在调试透视图中,转到“断点”选项卡,然后单击带有!的小图标)。
勾选“已捕获”和“未捕获”选项 - 现在当您触发NPE时,您将立即停止,并且您可以逐步检查并查看它是如何处理的以及为什么您没有获取堆栈跟踪。
toString()
只返回异常名称和可选消息。我建议调用
exception.printStackTrace()
如果你需要转储消息,或者需要详细信息:
StackTraceElement[] trace = exception.getStackTrace()
虚拟机会对已经被抛出多次的异常停止输出堆栈跟踪信息,这是C2编译器中的一种优化。
根据OpenJDK源代码显示,此优化适用于以下异常:
-NullPointerException(空指针异常) -ArithmeticException(算术异常) -ArrayIndexOutOfBoundsException(数组越界异常) -ArrayStoreException(数组存储异常) -ClassCastException(类转换异常)
java.lang.NullPointerException:
at com.company.product.MyTest.test(MyTest.java:37)
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)
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();
}
-XX: -OmitStackTraceInFastThrow
的更多信息,请参见 https://dev59.com/eG445IYBdhLWcg3w3N6z。 - Vadzim