Java中没有StackTrace的NullPointerException

时间:2010-03-09 18:23:53

标签: java nullpointerexception

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

java.lang.NullPointerException

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

10 个答案:

答案 0 :(得分:324)

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

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

要了解如何在HotSpot JVM grab a copy of it中实现此功能,并搜索全局变量OmitStackTraceInFastThrow。上次我查看代码(2019年)时,它位于graphKit.cpp文件中。

答案 1 :(得分:57)

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

LOG.error(exc);

而不是典型的

LOG.error("Some informative message", e);
通过懒惰或者可能只是不考虑它。不幸的是,它没有像你期望的那样表现。记录器API实际上将Object作为第一个参数,而不是字符串 - 然后它在参数上调用toString()。因此,它不是获得漂亮的漂亮堆栈跟踪,而是打印出toString - 在NPE的情况下它是非常无用的。

也许这就是你所经历的?

答案 2 :(得分:24)

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

请仔细查看日志。你可能会找到罪魁祸首。

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

答案 3 :(得分:19)

以下是解释:Hotspot caused exceptions to lose their stack traces in production – and the fix

我在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决定使用预分配异常的限制......

答案 4 :(得分: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。

答案 5 :(得分:4)

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

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

答案 6 :(得分:1)

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

exception.printStackTrace()

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

 StackTraceElement[] trace = exception.getStackTrace()

答案 7 :(得分:1)

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

以下是可能发生的事情的一些可能解释:

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

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

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

  • 正在记录的异常重载了一些隐藏堆栈跟踪的方法。如果是这种情况,异常将不是真正的NullPointerException,而是NPE的一些自定义子类型甚至是一些未连接的异常。

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

答案 8 :(得分:0)

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

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();
    }

答案 9 :(得分:0)

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

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

当通过Maven的万无一失运行测试时,打印了这个堆栈跟踪。

另一方面,在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)