Java:不可能的NullPointerException如何仍然发生?

Java:不可能的NullPointerException如何仍然发生?,java,nullpointerexception,Java,Nullpointerexception,我刚刚收到我们软件的以下错误报告: java.lang.NullPointerException at java.util.Arrays.equals(Unknown Source) at our.app.OurMain(OurMain.java:13) 在Windows上的JRE 1.7.045中会出现这种情况,数组的相应源代码。equals是: public static boolean equals(byte[] a, byte[] a2) { if (a==a2

我刚刚收到我们软件的以下错误报告:

java.lang.NullPointerException
    at java.util.Arrays.equals(Unknown Source)
    at our.app.OurMain(OurMain.java:13)
在Windows上的JRE 1.7.045中会出现这种情况,
数组的相应源代码。equals
是:

public static boolean equals(byte[] a, byte[] a2) {
    if (a==a2)
        return true;
    if (a==null || a2==null)
        return false;

    int length = a.length;
    if (a2.length != length)
        return false;

    for (int i=0; i<length; i++)
        if (a[i] != a2[i])
            return false;

    return true;
}

这里显然没有办法引发
NullPointerException
。怎么会这样呢?可以认为错误报告是可信的。

如果您的数组实际上是“
java.lang.Byte
”数组,并且其中一个值为null,则可能会发生这种情况,因此在取消装箱时(
a[i]!=a2[i]
)会出现此异常。

您可以使用javap检查字节码指令。或者是逆向工程工具

进行单元测试:

  • a、 a2:4例无效或无效
  • a[0]是否为空,a2[0]是否为空
上面区分了数组上的NPE或数组项

我非常模糊的猜测:您正在将
字节[]
(对象)字节[]
(而不是
字节[]
!)进行比较,当字节[i]为空时,隐式
字节值()也会引发空指针异常


然而,我无法立即看到如何调用该错误。也许会叫另一个相等的?我发现java.util.Arrays.equals(未知源代码)可疑。我希望JRE/SDK的rt.jar包含行号信息。
因此,可能有人在该系统上安装了其他JDK,可能是针对嵌入式设备的JDK,或者是其他一些实验性的JDK或其他东西,导致您使用与以前不同的JRE。

这并不是一个答案,但因为它太长,所以作为一个注释

一个还没有被问到的问题是:问题是什么时候开始出现的?在您的软件进行特定更新后,还是突然更新?您可能无法追踪它首次出现的确切日期,但如果它可以与时间关联,则很可能是由于软件发生更改(例如,您是否捆绑JRE?)而导致问题。然后,您将有条不紊地将已知的错误前版本与第一个显示错误的版本之间的更改区分开来

如果它是突然出现的,最有可能的问题来源(据我所知,从您所披露的信息)隐藏在您的软件的执行环境中的某个地方(可能不在您的直接控制之下)。它可能是JRE本身、相关的库或系统服务,甚至可能是特定的硬件和软件组合(信不信由你,有时很明显,即使是工作站的BIOS也会产生巨大的影响:)

为了提高找到问题原因的机会,您需要收集错误实际出现在哪个环境中的信息,并尽可能多地收集这些信息(至少JRE版本,32/64位,操作系统;最好安装补丁,CPU型号;最好包括掩码集修订版,主板型号;最好包括BIOS版本和主板修订版)。不要忘记导致问题的确切版本或您的软件。如果您的用户群具有非常同质的环境(例如,在大公司中,仅购买了少数工作站型号,可能全部来自同一供应商)与用户群非常异构(例如,许多独立客户使用完全不同的配置)相比,这些小细节更令人感兴趣

如果有足够的数据,就会出现一种模式(所有错误报告都有一个共同点,比如一个特定的JRE;或者一组JRE版本、特定的工作站模型等等)

如果可能的话,让您的用户与您合作(有意改变遇到问题的机器/用户的环境)测试候选对象。这可能涉及安装JDK以获取更多错误上下文、更改VM设置等


只有一个粗略的大纲,但如果没有快速的解决方案,从长远来看,系统的方法最有可能产生一个解决方案。

确保您正在执行此版本的代码,而不是使用
a.equals(b)的早期版本
而不是
a==b
?请显示完整的堆栈跟踪,并标记发生异常的行。JIT错误或硬件故障始终是可能的。此错误是否可以复制?@mstrap好的,如果地址恰好对齐(例如0x10000h),一个翻转的位可以将有效引用变为null虽然我没有关于比特错误概率的实际数字来源,但从1到10^-15顺序的数字是我读到的“粗略猜测”。我肯定不会排除这种可能性。至于一个实际的JIT错误,我不知道如何估计它的可能性。由于Arrays类一直存在,我认为一个破坏该代码的JIT错误会更快出现。但这只是猜测而已…-Xint强制VM进入解释模式(预计性能会大幅下降),这会使JIT消失。如果错误消失,则强烈表明JIT是原因。如果错误集中在一个或两个用户上,我只会怀疑硬件问题(确保您没有看到偏见,因为这些用户更可能报告)。要有系统地解决此问题,请仔细跟踪报告,并尽可能多地将它们与上下文信息配对-希望您能看到指向源的模式。Byte[]和Byte[]作为方法参数是不可互换的,从Byte[]到Byte[]没有自动转换如果两者都是Byte[]的话,您是对的然后将使用Arrays.equals(Object[],Object[]),其中最有可能不会引发此异常。您对此有完整的堆栈跟踪吗?为什么要
Arrays.equals(Object[]a,Object[]a2)
是否可以使用?即使是这样,NPE怎么可能在那里出现?如果它们的数组不是字节数组,而是java.lang.byte数组,那么将使用它们。这仍然可能
final byte[] b1 = ... // populate array
final byte[] b2 = ... // populate array
final boolean equal = Arrays.equals(b1, b2);