Native Imageでのネイティブメモリ追跡 (NMT)

ネイティブメモリ追跡(NMT)は、アプリケーションのオフヒープメモリ使用量を記録するサービス機能です。「オフヒープメモリ」という用語は、「ネイティブメモリ」または「非管理メモリ」と互換性がある場合に使用されることがあります。これは基本的に、ガベージコレクタによって管理されないメモリを意味します。

HotSpot JVMとは異なり、Native Imageは主にガベージコレクタによって管理される収集されたヒープ上のメモリを使用します。ただし、管理されたヒープでの割り当てを避けるために、Native Imageによってネイティブメモリが使用される場所はまだ多くあります。例としては、JFR、ガベージコレクタ、およびヒープダンプなどがあります。ネイティブメモリは、`Unsafe#allocateMemory(long)`を使用してアプリケーションレベルで直接要求することもできます。

ネイティブメモリ追跡の有効化 #

NMTサポートはデフォルトで無効になっており、ビルド時に明示的に有効にする必要があります。

NMTでネイティブ実行可能ファイルをビルドするには、`--enable-monitoring=nmt`オプションを使用します。NMTがビルド時に含まれている場合、実行時には常に有効になります。これは、実行時にNMTの有効/無効を切り替えることができるHotSpotとは異なります。

native-image --enable-monitoring=nmt YourApplication

ネイティブ実行可能ファイルからアプリケーションを起動するときに `-XX:+PrintNMTStatistics` を追加すると、NMTはアプリケーションが完了したときに標準出力にレポートを書き出すように指示します。

./yourapplication -XX:+PrintNMTStatistics

パフォーマンス #

Native Imageでは、NMTのCPUとメモリ消費量の両方が非常に最小限です。JFRなどの他のサービス機能と比較して、NMTのオーバーヘッドは比較的非常にわずかです。

NMTのJFRイベント #

OpenJDK JFRイベントの `jdk.NativeMemoryUsage` と `jdk.NativeMemoryUsageTotal` は、Native Imageでサポートされています。

アクセスできるNative Image固有のJFRイベントが2つあります: `jdk.NativeMemoryUsagePeak` と `jdk.NativeMemoryUsageTotalPeak`。これらのNative Image固有のイベントは、OpenJDKから移植されたJFRイベントでは公開されないピーク使用量データを公開するために作成されました。これらの新しいイベントは実験的としてマークされています。JDK Mission Controlなどのソフトウェアで表示するには、実験的イベントを有効にする必要がある場合があります。

これらのJFRイベントをNMTに使用するには、`native-image`ツールを呼び出すときに`--enable-monitoring=jfr,nmt`オプションを渡してJFR監視を有効にし、実行時にJFR記録を開始します。(詳細については、Native ImageでのJDK Flight Recorder(JFR) を参照してください)。

新しいイベントが `jfr` コマンドラインツールを使用して表示された場合の例を以下に示します

jfr print --events jdk.NativeMemoryUsagePeak recording.jfr 

jdk.NativeMemoryUsagePeak {
  startTime = 13:18:50.605 (2024-04-30)
  type = "Threading"
  peakReserved = 424 bytes
  peakCommitted = 424 bytes
  countAtPeak = 4
  eventThread = "JFR Shutdown Hook" (javaThreadId = 63)
}

jdk.NativeMemoryUsagePeak {
  startTime = 13:18:50.605 (2024-04-30)
  type = "Unsafe"
  peakReserved = 14.0 kB
  peakCommitted = 14.0 kB
  countAtPeak = 2
  eventThread = "JFR Shutdown Hook" (javaThreadId = 63)
}

制限事項 #

HotSpotでは、NMTにはサマリーモードと詳細モードの2つのモードがあります。Native Imageでは、現在NMTサマリーモードのみがサポートされています。コールサイト追跡を有効にする詳細モードは利用できません。ベースラインのキャプチャもまだできません。これらの追加機能のサポートに関心がある場合は、GitHubのGraalVMプロジェクトにリクエストを提出してください。

(JDK 23用GraalVMの時点で)現在利用可能な機能は、malloc追跡のみです。

HotSpotと同様に、Native ImageはVMレベルでの割り当てと`Unsafe#allocateMemory(long)`で行われた割り当てのみを追跡できます。たとえば、ライブラリコードまたはアプリケーションコードがmallocを直接呼び出すと、その呼び出しはNMTアカウンティングをバイパスして追跡されません。

参考資料 #

お問い合わせ