Java:int数组使用非零元素进行初始化
根据JLS,一个int
数组在初始化之后应该被零填充。 但是,我面临的情况并非如此。 这种行为首先发生在JDK 7u4中,并且也出现在以后的所有更新(我使用64位实现)中。 以下代码引发exception:
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执行代码块编译之后发生exception,并且不会出现-Xint
标志。 此外, Arrays.fill(...)
语句(与此代码中的所有其他语句一样)是必需的,如果不存在,则不会发生exception。 很明显,这个可能的bug被一些JVM优化限制了。 任何想法的原因这样的行为?
更新:
我在HotSpot 64位服务器虚拟机,Gentoo Linux上的1.7.0_04到1.7.0_10上的Java版本,Debian Linux(内核3.0版本)和MacOS Lion上看到了这种行为。 这个错误总是可以用上面的代码重现。 我没有用32位JDK或Windowstesting这个问题。 我已经向Oracle发送了一个错误报告(bug id 7196857),并且会在几天内出现在公共的Oracle错误数据库中。
更新:
Oracle在他们的公共bug数据库中发布了这个bug: http : //bugs.sun.com/bugdatabase/view_bug.do?bug_id=7196857
在这里,我们正面临JIT编译器中的一个错误。 编译器确定分配的数组在Arrays.fill(...)
分配Arrays.fill(...)
填充,但在分配和填充之间使用的检查是错误的。 所以,编译器执行非法优化 – 它跳过分配数组的调零。
这个bug被放置在Oracle bug跟踪器( bug id 7196857 )中。 不幸的是,我并没有等待甲骨文公司澄清以下几点。 正如我所看到的,这个bug是操作系统特定的:它在64位Linux和Mac上是完全可重现的,但正如我从评论中看到的那样,它在Windows上(对于相似版本的JDK)不是经常重现。 此外,这将是很高兴知道这个错误将被修复。
目前只有build议:不要使用JDK1.7.0_04或更高版本,如果您依赖于新声明的数组的JLS。
10月5日更新:
在2012年10月4日发布的JDK 7u10(早期访问)的新Build 10中,该错误至less在Linux操作系统(我没有为其他testing)上修复。 感谢@Makoto,他发现这个bug在Oracle bug数据库中不再可供公众访问。 不幸的是,我不知道甲骨文从公共访问中删除它的原因,但它可以在Google caching中使用 。 此外,这个bug也引起了Redhat的注意: CVE-2012-4420 ( bugzilla )和CVE-2012-4416 ( bugzilla )被分配到这个漏洞。
我在你的代码中做了一些改变。 这不是整数溢出的问题。 看到代码,它在运行时抛出一个exception
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++; }