Java:int 数组使用非零元素初始化

2022-08-31 08:29:38

根据 JLS,数组应该在初始化后由零填充。但是,我面临的情况并非如此。这种行为首先发生在JDK 7u4中,也发生在所有以后的更新中(我使用64位实现)。下面的代码引发异常:int

public static void main(String[] args) {
        int[] a;
        int n = 0;
        for (int i = 0; i < 100000000; ++i) {
            a = new int[10];
            for (int f : a)
                if (f != 0)
                  throw new RuntimeException("Array just after allocation: "+ Arrays.toString(a));
            Arrays.fill(a, 0);
            for (int j = 0; j < a.length; ++j)
                a[j] = (n - j)*i;
            for (int f : a)
                n += f;
        }
        System.out.println(n);
    }

该异常发生在 JVM 执行代码块编译之后,并且不会出现带有标志的情况。此外,该语句(与此代码中的所有其他语句一样)是必需的,如果异常不存在,则不会发生异常。很明显,这个可能的错误与一些JVM优化有关。出于这种行为的原因,有什么想法吗?-XintArrays.fill(...)

更新:
我在HotSpot 64位服务器VM上看到此行为,Java版本从1.7.0_04到Gentoo Linux,Debian Linux(内核3.0版本)和MacOS Lion上的1.7.0_04到1.7.0_10。此错误始终可以使用上面的代码重现。我没有用32位JDK或Windows测试这个问题。我已经向Oracle发送了一份错误报告(错误id 7196857),它将在几天内出现在公共Oracle错误数据库中。

更新:
Oracle在其公共错误数据库中发布了此错误:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7196857


答案 1

在这里,我们面临着JIT编译器中的一个错误。编译器确定在 中分配后填充分配的数组,但对分配和填充之间的使用检查是错误的。因此,编译器执行非法优化 - 它跳过分配数组的清零。Arrays.fill(...)

此错误放置在Oracle错误跟踪器中(错误id 7196857)。不幸的是,我没有等待Oracle对以下几点的任何澄清。正如我所看到的,这个错误是特定于操作系统的:它在64位Linux和Mac上绝对可以重现,但是,正如我从评论中看到的那样,它不会在Windows上定期重现(对于类似版本的JDK)。此外,很高兴知道何时修复此错误。

目前只有建议:如果您依赖JLS来获取新声明的数组,请不要使用JDK1.7.0_04或更高版本。

10月5日更新:

2012年10月4日发布的JDK 7u10(抢先体验)的新版本10中,这个错误至少在Linux操作系统上得到了修复(我没有测试其他错误)。感谢@Makoto,他发现此错误不再可用于Oracle错误数据库中的公共访问。不幸的是,我不知道甲骨文将其从公共访问中删除的原因,但它可以在Google缓存中使用。此外,这个错误引起了Redhat的注意:CVE标识符CVE-2012-4420bugzilla)和CVE-2012-4416bugzilla)被分配给了这个漏洞。


答案 2

我对您的代码进行了一些更改。这不是整数溢出的问题。查看代码,它会在运行时引发异常

    int[] a;
    int n = 0;
    for (int i = 0; i < 100000000; ++i) {
        a = new int[10];
        for (int f : a) {
            if (f != 0) {
                throw new RuntimeException("Array just after allocation: " + Arrays.toString(a));
            }
        }
        for (int ii = 0, len = a.length; ii < len; ii++)
            a[ii] = 0;
        for (int j = 0; j < a.length; ++j)
            a[j] = Integer.MAX_VALUE - 1;
        for (int j = 0; j < a.length; ++j)
            n++;
    }