没有StackTrace的Java中的NullPointerException


332

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

java.lang.NullPointerException

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


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

这里没有涉及线程,只是普通的旧Java。
爱德华·施特恩

1
@Bozho-不-尚不确定如何重现NullPointer。
爱德华·施特恩


有关-XX:-OmitStackTraceInFastThrowdup的更多信息:stackoverflow.com/questions/4659151/…–
Vadzim

Answers:


406

您可能正在使用HotSpot JVM(最初由Sun Microsystems,后来由Oracle收购,又是OpenJDK的一部分),它执行了很多优化。要获取堆栈跟踪,需要将选项传递-XX:-OmitStackTraceInFastThrow给JVM。

优化是,当第一次发生异常(通常为NullPointerException)时,将打印完整的堆栈跟踪,并且JVM会记住堆栈跟踪(或者可能只是代码的位置)。当该异常经常发生时,将不再打印堆栈跟踪,这既可以实现更好的性能,又不会使相同的堆栈跟踪充满日志。

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


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

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

34
我以为我想补充的信息的附加位,当堆栈跟踪被优化掉,这是因为它已经得到了充分至少一次处理:jawspeak.com/2010/05/26/...
sharakan

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

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

61

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

LOG.error(exc);

而不是典型的

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

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

也许这就是您所经历的?


+1:这可以解释所描述的行为,并且您不是唯一发现此行为的人:)
彼得·朗

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

5
可以,但是策略并不意味着它总是可以正确执行!至少值得一提。
史蒂文·史兰斯克

没错,但在这种情况下是;-)
爱德华·施特恩

28

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

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

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


2
该错误已关闭,但仍需要-XX:-OmitStackTraceInFastThrow标志来解决性能优化问题。
约书亚·戈德堡

我最近经常看到这种情况。关于什么可能导致此问题或如何解决的任何线索?测井系统可能已经运行了好几天,实际原因已经消除,不要介意乏味的搜索...
Pawel Veselov 2012年

5
Pawel,您是否尝试过-XX:-OmitStackTraceInFastThrowJoshua建议的JVM标志?另请参阅stackoverflow.com/a/2070568/6198
马特·索尔尼特

1
这就是给我们的。谢谢。
Andrew Cheong

20

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

我已经在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();
        }
    }

对于此特定的代码片段,JVM决定使用预分配的异常的局限性是12288次迭代(+ frequency?)。


10

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())记录了这些信息。
爱德华·施特恩

1
您是否尝试过使用getStackTrace()以确保记录器没有问题?
彼得·朗

1
如果使用的是log4j,请确保将异常作为参数的一部分发送到log方法。我将以此发布答案。
拉维·瓦劳

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

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

4

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

选中“ caught”和“ uncaught”两个选项-现在,当您触发NPE时,您将立即断点,然后可以逐步了解它的处理方式以及为什么没有得到堆栈跟踪。


1

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

exception.printStackTrace()

转储邮件,或者如果您需要血腥细节:

 StackTraceElement[] trace = exception.getStackTrace()

参见上文-我打错了-我正在使用printStackTrace()。
爱德华·施特恩

1

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

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

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

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

  • 信息来自与您认为不同的地方。例如,它实际上是某种第三方库方法,或者是较早的调试尝试遗留下来的一些随机内容。

  • 正在记录的异常使一些方法变得难以理解,从而使stacktrace变得晦涩难懂。如果真是这样,该异常将不是真正的NullPointerException,而是某些NPE的自定义子类型,甚至是一些未连接的异常。

我认为,最后一种可能的解释是不太可能的,但是人们至少会考虑这样做以“防止”逆向工程。当然,只有这样才能真正为诚实的开发人员带来困难。


1

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

0

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

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();
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.