Shenandoah GCの機能診断

Red Hat で Java Platform Advocate として OpenJDK を担当している伊藤ちひろ(@chiroito)です。

この記事は、OpenJDK のWikiページ、https://wiki.openjdk.java.net/display/shenandoah/Main の一部を翻訳した記事です。こちらが最後の記事になります。

翻訳の各リンクはこちらです。

目次

機能診断

このセクションでは、Shenandoahの診断とデバッグの方法について説明します。

これらは、問題箇所を絞り込むためにできるステップです。

  1. -XX:+ShenandoahVerifyで実行します。これはGCバグに対する防御の最初の手段です。これはリリースとfastdebugの両方のビルドで利用可能です。Verifierが問題を特定した場合、それはGCバグである可能性が高いです。これをよりよく診断するために、簡単な再現ツールがあると便利でしょう。多くの場合、GCで以前何が起こったかが重要です。例えば、GCで最後に行われたアクションなど。その履歴は通常、関連する hs_err_pidXXXX.log に記録されているので、バグを報告する際にそれを完全に含めることを確認してください。

  2. fastdebugビルドで実行します。多くの場合、これで意味のあるアサートメッセージが表示されます。これは、GCが機能的な異常を検出した最も早いタイミングを指しています。そして、Shenandoahは、たくさんアサートします。これらのビルドは、configureに--enable-debugを追加し、再ビルドすることによって生成できます。例によって、hs_err_pidXXXX.logは、アサーション失敗を調査するのに役立つ環境と履歴データを便利に記録しています。

  3. -XX:ShenandoahGCHeuristics=passiveで実行すると、stop-the-worldを伴うGCのみを行い、ほとんどの並行処理を行わないようにします。passiveモードで問題がなくなれば、並行フェーズやバリアでのバグであるはずです。

  4. -Xint (インタープリタのみ), -XX:TieredStopAtLevel=1 (C1のみ), -XX:-TieredCompilation (インタープリタとC2のみ) - どのモードで失敗し、どのモードで失敗しないかを分析するために異なるコンパイラで実行します。これにより、インタープリタ、C1、またはC2でのバリア処理または最適化に問題があるかどうかが明らかになります。これは通常、fastdebug ビルドと組み合わせると便利です。なぜなら、コンパイラもアサートするからです。

  5. -XX:ShenandoahGCHeuristics=aggressiveで実行します。このヒューリスティックは、連続してGCを実行し、全ての空でない領域を退避させます。Shenandoahは、ほとんどのGCの重い仕事を並行して行うので、これは、アプリケーションの実行をブロックしません。しかし、このモードでは、GCはより多くのサイクルを消費し、アプリケーションを遅くします。このモードでVerifierを有効にすると、おそらく実用的でないレベルまで性能が低下することに注意してください。

  6. -XX:+ShenandoahVerifyOptoBarriers(C2の理想グラフの障壁を検証)、-XX:VerifyStrictOopOperations(Oop比較が正しく行われているかを検証するための追加チェックを行う)でさらに検証を追加します。

一般的なデバッグのテクニックはShenandoahにも適用されます:

  1. 問題をよりよく理解するために、失敗したアサートの周りのコードにロギング文を入れてください。十分なロギングがあれば、コレクターで起こったことを全て辿れます。
  2. コード中の疑わしい部分の周りにさらにアサート文を追加します。shenandoahAsserts.hpp のマクロ定義を見て、どのような豊富なアサートが利用可能かを確認しましょう。
  3. ネイティブデバッガをアタッチします。例えばgdb。VMに -XX:OnError="gdb - %p" (%pはプロセスのPIDに置き換えられる)と指定して、失敗時に外部アクションを実行するよう依頼します。
  4. 簡単な再現プログラム作成し、Shenandoahの開発者に渡します:)

ソースからビルド

これは、最新かつ最高のバージョンを実行することを保証するものです。一部の機能やバグフィックスは、古いバージョンのJDKでは利用できない場合があります。古いバージョンのJDKは、より安定しているはずです。

./configure--enable-debug を追加すると、より多くの診断を行う "fastdebug" ビルドが生成されます。

ワークスペースのダウンロードに時間がかかりすぎると感じるかもしれません。特に jdk10+ のワークスペースはそうです。そのような場合は、ワークスペースの tarball をここからダウンロードできます。

https://builds.shipilev.net/workspaces/

# JDK master:
$ hg clone http://hg.openjdk.java.net/jdk/jdk shenandoah
 
# JDK 11u:
$ hg clone http://hg.openjdk.java.net/jdk-updates/jdk11u shenandoah
 
# JDK 8u:
$ hg clone http://hg.openjdk.java.net/shenandoah/jdk8 shenandoah
 
$ cd shenandoah/
# JDK 11移行を設定してビルド:
$ sh ./configure
$ make images
 
# JDK 8を設定してビルド:
$ sh ./get_source.sh
$ sh ./configure
$ make images
  
 
# JDK 11移行を実行!:
$ build/linux-x86_64-normal-server-release/images/jdk/bin/java -XX:+UseShenandoahGC -Xlog:gc
[...][info][gc] Using Shenandoah
  
# JDK 8を実行!:
$ build/linux-x86_64-normal-server-release/images/j2sdk-image/bin/java -XX:+UseShenandoahGC -version
openjdk version "1.8.0-internal"
OpenJDK Runtime Environment (build 1.8.0-internal-shade_2016_12_19_15_52-b00)
OpenJDK 64-Bit Server VM (build 25.71-b00, mixed mode)

注意:OpenJDKは通常、すべての警告をエラーとして扱ってコンパイルされます。新しいコンパイラは、コードベースがまだ追いついていない警告を多く持っているかもしれません。そのような場合は、./configure--disable-warnings-as-errors を渡すことができます。

ソースからビルドする場合、すべてのケースでテストを実行することは任意ですが、推奨されます。これは、Shenandoahが現在ターゲットにしている以上のプラットフォームや、新しすぎる、あるいは古すぎるツールチェインでビルドする場合に、特に重要です。テストを実行するには、jtregが必要であり、最初にfastdebugビルドに対してテストを実行することは、理にかなっています。

# jtreg を https://ci.adoptopenjdk.net/view/Dependencies/job/jtreg/ からダウンロードして解凍
 
# jtreg をビルド成果物と接続:
$ sh ./configure --with-jtreg=<jtreg folder> --with-debug-level=fastdebug
$ sh ./configure --with-jtreg=<jtreg folder> --with-debug-level=release
 
 
# テストを実行:
$ CONF=linux-x86_64-normal-server-fastdebug make images run-test TEST="tier3_gc_shenandoah" 
$ CONF=linux-x86_64-normal-server-release   make images run-test TEST="tier3_gc_shenandoah"

リソース

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません。その内容については非公式見解を含みます。