JLSによると、int
配列は初期化の直後にゼロで埋められる必要があります。しかし、そうではない状況に直面しています。このような動作はJDK 7u4で最初に発生し、その後のすべての更新でも発生します(64ビット実装を使用しています)。次のコードは例外をスローします。
_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がコードブロックのコンパイルを実行した後に例外が発生し、_-Xint
_フラグでは発生しません。さらに、Arrays.fill(...)
ステートメント(このコードの他のすべてのステートメント)が必要であり、存在しない場合は例外は発生しません。この可能性のあるバグが、JVMの最適化に制限されていることは明らかです。そのような行動の理由のためのアイデアはありますか?
更新:
HotSpot 64ビットサーバーVMでこの動作が見られます。Javaバージョン) Lion:このエラーは上記のコードで常に再現できます。32ビットJDKまたはWindowsでこの問題をテストしていません。Oracleにバグレポートを送信しました(バグID 7196857)。数日でバグデータベース。
更新:
Oracleは、このバグを公開バグデータベースで公開しました。 http://bugs.Sun.com/bugdatabase/view_bug.do?bug_id=7196857
ここで、JITコンパイラのバグに直面しています。コンパイラは、Arrays.fill(...)
での割り当て後に割り当てられた配列がいっぱいになったと判断しますが、割り当てといっぱいの間の使用のチェックに誤りがあります。そのため、コンパイラは不正な最適化を実行します-割り当てられた配列のゼロ化をスキップします。
このバグはOracleバグトラッカーに配置されます( bug id 7196857 )。残念ながら、次の点に関するオラクルからの説明を待ちませんでした。ご覧のとおり、このバグはOS固有のものです。64ビットLinuxおよびMacで完全に再現可能ですが、コメントからわかるように、Windows(JDKの類似バージョン)では定期的に再現されません。さらに、このバグがいつ修正されるかを知っておくといいでしょう。
現時点で唯一のアドバイスがあります。新しく宣言された配列をJLSに依存している場合は、JDK1.7.0_04以降を使用しないでください。
10月5日の更新:
2012年10月4日にリリースされたJDK 7u10(早期アクセス)の新しい Build 1 では、このバグは少なくともLinux OSで修正されました(他のテストは行いませんでした)。 @B残念ながら、Oracleがパブリックアクセスから削除した理由はわかりませんが、Googleで利用可能です cache 。また、このバグはRedhatの注目を集めました:CVE識別子 CVE-2012-442 ( bugzilla )および CVE-2012-4416 ( bugzilla )この欠陥に割り当てられました。
コードに変更を加えました。整数オーバーフローの問題ではありません。コードを参照してください、実行時に例外をスローします
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++;
}