[Java] Crashes in ZIP_GetEntry

原文はこちら。
https://blogs.oracle.com/poonam/entry/crashes_in_zip_getentry

先日、以下のようなスタックトレース付きで、アプリケーションクラッシュに関する数多くの報告が、様々なお客様や製品グループから寄せられました。
Stack: [0xb0c00000,0xb0c80000],  sp=0xb0c7c890,  free space=498k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C  [libc_psr.so.1+0x700]  memcpy+0x2f8
C  [libzip.so+0xd19c]
C  [libzip.so+0x2380]  ZIP_GetEntry+0xe4
C  [libzip.so+0x2800]  Java_java_util_zip_ZipFile_getEntry+0xc4
j  java.util.zip.ZipFile.getEntry(JLjava/lang/String;Z)J+0
j  java.util.zip.ZipFile.getEntry(JLjava/lang/String;Z)J+0
j  java.util.zip.ZipFile.getEntry(Ljava/lang/String;)Ljava/util/zip/ZipEntry;+31
j  java.util.jar.JarFile.getEntry(Ljava/lang/String;)Ljava/util/zip/ZipEntry;+2
j  java.util.jar.JarFile.getJarEntry(Ljava/lang/String;)Ljava/util/jar/JarEntry;+2
ほとんどの場合、JVMインスタンス実行中にアクセスしているjarファイルを変更、上書きした際にZIP_GetEntryにてクラッシュが発生しています。パフォーマンスの理由により、HotSpot JVMのメモリはmmapを使い各Jarファイルのセントラルディレクトリ構造にマップします。こうすることで、Jarファイルからエントリを読み取る必要がある都度セントラルディレクトリ構造データをディスクから読み取ることを避けています。Jarファイルをディスク上で変更、上書きする場合、以前に読み取ったJVMのデータのコピーがディスク上のJarファイルと一致しなくなり、変更されたJarファイルからエントリを読み取り、ロードしようとするとアプリケーションクラッシュが発生することがあります。

Java 1.6.0_23以後では、プロパティを使ってJarファイルのセントラルディレクトリ構造メモリマッピングのマッピングを抑止することができます。
-Dsun.zip.disableMemoryMapping=true
このプロパティを有効にすると、JVMはJarファイルのエントリを読み出す都度ディスク上のJarファイルからセントラルディレクトリ構造を読み取る必要があるため、アプリケーションのパフォーマンスに影響することにご注意ください。そのため、JVMがJarファイルのイメージをロードしている間は、Jarファイルを変更したり上書きしたりしないようにすることがベストです。

Java 9では、このZIPクラッシュを以下の機能強化で解決しました。
JDK-8142508: To bring j.u.z.ZipFile's native implementation to Java to remove the expensive jni cost and mmap crash risk
https://bugs.openjdk.java.net/browse/JDK-8142508
この変更に対するコード・レビューのスレッドは以下からどうぞ。
RFR: JDK-8142508: To bring j.u.z.ZipFile's native implementation to Java to remove the expensive jni cost and mmap crash risk
http://mail.openjdk.java.net/pipermail/core-libs-dev/2015-November/036495.html
この機能強化はmmapを使うZIPファイルのネイティブ実装をJava実装に置き換え、上述のアプリケーションクラッシュのリスクを除去しています。

0 件のコメント:

コメントを投稿