個人的にJava 11で一番嬉しい新機能はFlight Recorderです。

Flight RecorderはOracle JDK 7u40から使える有償機能でしたが、OSS化されJava 11からOpenJDKに入りました。
(Flight Recorderは元々JRockitに搭載されていたもので、JRockitがHotSpot VMに統合されたのが7u40らしい)

Mission ControlもOSS化されていますが、OpenJDKには含まれていないので別途ダウンロードが必要です。

Java 11のFlight RecorderとMission Controlの情報はまだ少ないので、まだ軽く触った程度ですが調べた内容をまとめておきます。



使用したバージョン

  • JDK: OpenJDK 11 GA (build: 28)
  • JDK Mission Control: 7 Early-Access (build: 07)


参考資料

Oracle JDK 11の 公式ドキュメント

2018/10/15時点ではまだ日本語訳はありませんが、以下の3つのドキュメントにFlight RecorderとMission Controlに関する情報があります。

  • javaコマンドのコマンドライン引数
  • 診断ツール
    Flight Recorderのオーバーヘッドに関して、上記ドキュメントのTroubleshoot Performance Issues Using Flight Recorderに以下の記載があります。
    オーバーヘッドはほとんどのアプリケーションで2%未満なので、標準的な設定で継続的に記録を取っても問題ないようです(アプリケーションのパフォーマンス要件次第だとは思いますが)
    The overhead for recording a standard time fixed recording (profiling recording) using the default settings is less than two percent for most applications. Running with a standard continuous recording generally has no measurable performance effect.
  • メモリリークのトラブルシューティング

その他、参考になりそうな資料



JVMオプション

上記公式ドキュメントのjavaコマンドのコマンドライン引数を見ると、Flight Recorderに関するオプションは以下の2つです
(-XX:+FlightRecorderはJDK 8u40以降不要になっています)

  • -XX:StartFlightRecording
    アプリケーション開始時点からFlight Recorderによる記録を開始するためのオプションです
    このオプションを使わずに、必要な時にjcmdやJMCから設定する事も可能
  • -XX:FlightRecorderOptions
    Flight Recorder自体のチューニングを行うオプションです
    上記Java Day Tokyo 2017 - JDK9 の JMC & JFRのプレビューのP12の「フライトレコーダ内部のイベント記録の流れ」を見ると、イメージが湧くと思います。
    今回は設定してませんが、記録対象のアプリケーションによっては、バッファのチューニングをした方が良いかもしれません。

Flight RecorderはjcmdやJMCから操作してスポット的に記録を取る事もできますが、
今回は、__「アプリケーション起動時から自動的に記録を開始して、必要に応じてMission Controlから状態を確認したり、予期せぬアプリケーションプロセスの異常終了時に後からFlight Recorder記録ファイルをJMCで解析する」__という使い方を想定しています。

JMCで接続するために、JMXのパラメータも必要です。 以下のパラメータなどを設定してください。

com.sun.management.jmxremote.port
com.sun.management.jmxremote.ssl
com.sun.management.jmxremote.authenticate

なお、JMXのパラメータは、アプリを動かす環境によって必要なパラメータが違うので注意してください。
以下がわかりやすいと思います。


プロファイルを取る場合の設定

今回は以下の設定をしてみます。
(なお、記録中でもJMCから記録設定を変更したり、新しい別の記録を合わせて取ったりも出来るようです)

※長くなって見にくいので、\マークでエスケープして改行しています。

-XX:StartFlightRecording=name=on_startup,\
filename=/root/flight_recording_$(date +"%Y-%m-%d_%H-%M-%S").jfr,\
dumponexit=true,\
delay=2m,\
maxsize=512m,\
settings=profile,\
path-to-gc-roots=true

name

必須ではないですが、何も設定しないとJMCで接続した時にデフォルトの 1 という名前になるので、設定しておく方がわかりやすいと思います。

filename

上記Java Day Tokyo 2017 - JDK9 の JMC & JFRのプレビューのP12の「フライトレコーダ内部のイベント記録の流れ」を見るとわかりますが、Flight Recorderの記録はまず内部のバッファに保存され、バッファがいっぱいになったらディスクに保存されます。
filenameはそのファイルの保存パスです。

dumponexit

JVMがシャットダウンしたときに実行中の記録をダンプするかどうかを指定します。
公式ドキュメントによると、このダンプファイルはfilenameで指定したファイルとは別に作成されるようです。

delay

delayは、アプリケーションの起動完了を待って記録を開始するための設定です。

どのくらい記録を取り続けるか?

関連するパラメータは以下です。

記録はディスク容量が許す限り取って良いと思うので、maxsizeだけ指定してみました。

  • duration
  • maxage
  • maxsize

settings

settingsにprofileを設定するとスタックトレースも記録に含まれるようになりますが、profileはオーバーヘッドが大きいです。
まあ、公式ドキュメントによると、プロファイルを取る場合でもオーバーヘッドは約2%みたいですが。

path-to-gc-roots

path-to-gc-rootsはルートへのパス情報を記録するかどうかのパラメータですが、収集に時間がかかるようになるため、メモリリーク調査する時だけonにするように公式ドキュメントには書かれています。


プロファイル不要の場合の設定

普段はsettingsとpath-to-gc-rootsを外しておくと良いと思います。
プロファイルを取らない場合(default)のオーバーヘッドは1%未満みたいです。

-XX:StartFlightRecording=name=on_startup,\
filename=/root/flight_recording_$(date +"%Y-%m-%d_%H-%M-%S").jfr,\
dumponexit=true,\
delay=2m,\
maxsize=512m


Mission Controlから接続してみる

Mission Controlから接続してFlight Recorderの記録を見てみます。

JMX接続設定を追加

JVM Browserのところで右クリックして、接続設定を追加します。

次に、JMXの接続情報を入力します。
(今回は、Dockerを使ってローカルで動かして、JMXのポートは8686にしています)

次に、JMXコンソールを開くか、Flight Recorderの記録を開始するかを選択する画面になりますが、この操作でFlight Recorderの記録を開始する必要はないので、JMXコンソールを開く方を選択します。
(どっちでも良いです)

JMX接続設定が作成され、JMXコンソールが開きました。
が、Flight Recorderの操作をする時にJMXコンソールは使わないので無視していいです。

JMX接続設定を作成する事がこの操作の目的です。
なお、このJMX接続設定作成の操作は1回やればOKです。

さて、ここからがFlight Recorderの操作です。
Flight Recorderの部分をクリックして開いてみましょう。

-XX:StartFlightRecordingオプションで設定した名前で記録が取られている事が確認できます。

右クリックメニューはこんな感じです。

Editを選択してみましょう。
以下のようなダイアログが開きます。

Event settingsのプルダウンリストを見ると、プリセットの2つの設定が確認できます。

  • Continuous: settings指定なしの場合のデフォルト
  • Profiling: settings=profile

Continuousを選択してみると、典型的なオーバーヘッドは1%未満と説明が表示されますね。

Profilingでは、典型的なオーバーヘッドは約2%と表示されます。


Flight Recorder記録を見てみる

記録を見るためには、ダンプしないといけません。

右クリックメニューから、以下のどちらかを選択します。

  • Dump whole recording: 記録全体をダンプする
  • Dump last part of recording: 記録の最後の部分だけをダンプする

どちらか選んでダンプしてみましょう。

JMCには自動分析機能が付いているので、問題がありそうな箇所がヒップアップされます。

他の項目も見れますので、Outlineから選択してみてください。

なお、Flight Recorderのダンプファイル(拡張子 .jfr)はローカルに保存されます。
Macの場合はホームディレクトリ直下に保存されました。
必要なファイルは別途保管したり、不要なファイルは削除したりしてください。



Flight Recorder API

今回は試せていませんが、上記のJava Day Tokyo 2018 - Java Mission Control 6.0 と 新しくなったJava Flight Recorder (PDF)で紹介されているFlight Recorder APIを使って、
監視対象アプリやフレームワークやライブラリに計測ロジックを実装していくと監視が捗りそうですね。



jlinkで生成したランタイムで動かす場合の注意点

jlinkに --bind-services オプションを追加してください。

@sundararajan_a-san, Thank you so much!



今回は以上です。