[Java, Linux] UseLargePages on Linux

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

JVMのオプションにJDK 5u5で導入されたUseLargePagesというものがあり、これを使うと、システムがラージメモリをサポートしていれば、システムからラージメモリページをリクエストすることができます。ラージメモリページのサポートの目的はプロセッサのTranslation-Lookaside Buffers(TLB)を最適化し、結果としてパフォーマンスを向上することです。

最近ラージメモリページを使っている際にいくつかのHotSpotのインスタンス(JDK7)がクラッシュするという現象がありました。
8013057: assert(_needs_gc || SafepointSynchronize::is_at_safepoint()) failed: only read at safepoint
https://bugs.openjdk.java.net/browse/JDK-8013057
8007074: SIGSEGV at ParMarkBitMap::verify_clear()
https://bugs.openjdk.java.net/browse/JDK-8007074

原因

これらのクラッシュの原因はmmapのLinuxプラットフォームでの動作方法にあります。ラージページのサポートがシステム上で有効になっている場合、LinuxプラットフォームでのHotSpotのcommit_memory()実装は、ラージページを使うmmapコールで、既に予約されたメモリをコミットしようとします。十分なサイズのラージページがない場合には、mmapコールは予約されたメモリをリリースできず、同じメモリ領域を他の割り当て(アロケーション)に利用できません。このために同じメモリ領域を使う異なる目的で使うと予期せぬ挙動を引き起こします。

症状

上記問題と共に、以下のようなスタックトレースを伴うクラッシュを目にすることがあります。
V  [libjvm.so+0x759a1a]  ParMarkBitMap::mark_obj(HeapWord*, unsigned long)+0x7a
V  [libjvm.so+0x7a116e]  PSParallelCompact::MarkAndPushClosure::do_oop(oopDesc**)+0xce
V  [libjvm.so+0x485197]  frame::oops_interpreted_do(OopClosure*, RegisterMap const*, bool)+0xe7
V  [libjvm.so+0x863a4a]  JavaThread::oops_do(OopClosure*, CodeBlobClosure*)+0x15a
V  [libjvm.so+0x77c97e]  ThreadRootsMarkingTask::do_it(GCTaskManager*, unsigned int)+0xae
V  [libjvm.so+0x4b7ec0]  GCTaskThread::run()+0x130
V  [libjvm.so+0x748f90]  java_start(Thread*)+0x100
この例では、ParMarkBitMapがマップした領域のアドレス0x00007f2cf656eef0に書き込もうとした時点でクラッシュしています。そしてそのメモリは(hs_err.logファイルによると)rt.jarに属しています。
7f2cf6419000-7f2cf65d7000 r--s 039dd000 00:31 106601532                  /jdk/jdk1.7.0_21/jre/lib/rt.jar
このバグが原因で、同じメモリ領域を2個の異なるアロケーションのためにマップするとこのクラッシュが発生します。

解決策

8013057については、Linuxプラットフォームでのmmapの不具合のエラー処理を強化し、これらの障害のための診断情報も追加しました。この不具合は7u40で修正されています。

8007074については、Linuxプラットフォームでラージページを利用する際に予約されたメモリマッピングロスの問題を修正しています。この修正の詳細は以下の通りです。
Review request (hs24): 8007074: SIGSEGV at ParMarkBitMap::verify_clear()
http://mail.openjdk.java.net/pipermail/hotspot-dev/2013-July/010117.html
JDK8で修正されますが、この内容は7u60にも取り込まれています。7u60のリリースは2014年5月を予定しています。

回避策

  1. JVMオプションでラージページの利用(-XX:-UseLargePages)を無効化する
  2. システムで利用可能なラージページのサイズを増やす。十分なサイズのラージページがシステムにある場合、メモリコミットの失敗のリスクを減らすことができ、このラージページの問題に遭遇する可能性が減る。ラージページのサイズを構成する方法は以下のリンクを参照すること。
    Java Support for Large Memory Pages
    http://www.oracle.com/technetwork/java/javase/tech/largememory-jsp-137182.html

その他の関連する修正

8026887: Make issues due to failed large pages allocations easier to debug
https://bugs.openjdk.java.net/browse/JDK-8026887
8013057の修正に伴い、メモリコミットの失敗に対する診断情報を追加しました。以前は以下のようなエラーメッセージを表示していました。
os::commit_memory(0x00000006b1600000, 352321536, 2097152, 0) failed;
error='Cannot allocate memory' (errno=12)
8026887のこの修正に伴い、ラージページが不足していることが原因でメモリコミットに失敗していることを示すようにエラーメッセージが修正されました。現時点では以下のようになっています。
os::commit_memory(0x00000006b1600000, 352321536, 2097152, 0) failed;
error='Cannot allocate large pages, falling back to small pages' (errno=12)
この変更は7u51に統合されました。

8007074に対する修正は7u60で利用できるようになります(7u51には取り込まれていません)ので、この変更(JDK-8026887)の結果、ラージページに関連するメモリコミット障害を示すエラーメッセージの表示がなされるため、より有益な情報を提供することになります。これらのメッセージをJVMのログで見かけた場合、バグ8007074が原因で予期せぬ挙動が起こる可能性があります。
8024838: Significant slowdown due to transparent huge pages
https://bugs.openjdk.java.net/browse/JDK-8024838
8007074の修正に伴い、顕著なパフォーマンスの低下が見られました。このリグレッションはJDK8でJDK-8024838として修正され、この内容はJDK 7u60にも取り込まれる予定です。

0 件のコメント:

コメントを投稿