extend-troubleshooting-oom-java
注釈:本資料はAI技術を用いて翻訳されています。
Overview
Java Extendアプリはガベージコレクタを使用してシステムメモリを自動的に管理します。しかし、次のような原因でメモリの問題が発生することがあります。
- 非効率なデータ構造
- 大きなオブジェクトへの参照を必要以上に長く保持すること
- メモリリーク
- 一般的な高メモリ使用量
ベストプラクティス
- 目的に合った適切なデータ構造を選択します。例えば、ソートが不要な場合はTreeMapよりもHashMapを使用します。ArrayListについては、想定されるサイズがわかっている場合、作成時にそのサイズを指定することで、コストのかかるリサイズ操作を最小限に抑えられます。
- Stringは不変であるため、文字列の連結は避けてください。代わりに
StringBuilderを使用します。 - 不要になったオブジェクトは、特に大きなオブジェクトの場合、コレクションからすぐに削除します。
- CPUとメモリのプロファイリングを開発サイクルに組み込み、メモリリークやパフォーマンスのボトルネックを早期に発見します。
- ガベージコレクションとヒープサイズを最適化します。パフォーマンス目標に基づいてガベージコレクションとヒープサイズを調整します。初期ヒープと最大ヒープ(
-Xms/Xmx)のサイズを調整することで、実行時のリサイズを防止できます。過度なガベージコレクションの動作を減らすために、ヒープサイズを十分に大きく設定してください。 - オブジェクトの生成を最小限に抑えるか、可能な限りオブジェクトを再利用します。頻繁に生成・破棄される高コストなオブジェクトについては、プールの使用を検討してください。
- 遅延初期化を活用し、必要になるまで生成を遅らせることで、初期メモリ消費を抑え、起動時間を改善します。
- 他のソースから取得するデータ量を制限します。
- ネイティブコードの使用は避けてください。ネイティブコードは通常、手動でのメモリ管理を必要とし、Java仮想マシン(JVM)のメモリ管理を回避してしまいます。ネイティブコードの誤った使用は、メモリリーク、クラッシュ、予期しない動作につながる可能性もあります。ネイティブコードを使用する場合は、ネイティブリソースを慎重に管理し、確実に解放されるようにしてください。
推奨ツール
CPUとメモリの使用状況を管理するために、次のツールの使用を推奨します。
IntelliJ Profiler
IntelliJ Profilerは、CPUとメモリの使用状況を分析してコードを最適化するための、さまざまなプロファイリング機能を備えたパフォーマンス分析ツールです。IntelliJをExtendアプリと統合するには、以下の手順に従います。
- Profile with IntelliJ Profilerを選択して、IntelliJでExtendアプリケーションを起動します。
- Run > Profile [アプリケーション名] with IntelliJ Profilerでアプリケーションを実行します。
- プロファイリングが完了したら、Stop Recording and Show Resultsをクリックします。CPU sampling - Flame Graphの結果が表示されます。

- 結果表示をCPU samplesとMemory samplesの間で切り替えます。以下の画像はMemory samplesビューでの結果を示しています。

詳細については、IntelliJ Profilerのドキュメント、およびCPUプロファイリングやメモリリークの発見に関するドキュメントを参照してください。
VisualVMを使用したIntelliJ Profiler
IntelliJ ProfilerをVisualVMと併用することで、Java Management Extensions(JMX)からのライブ結果や、保存されたJava Flight Recorder(JFR)ファイルからの結果を取得できます。以下の手順に従います。
- VisualVMで、Localの下にある実行中のアプリケーションを選択し、そのアプリケーションをダブルクリックして接続します。ライブ接続すると、VisualVMはCPUとメモリ使用量のライブモニタリング結果を表示します。
- その後、次の操作を行うことができます。
- Samplerタブに移動して、CPUとメモリのサンプリングを開始します。
- CPUサンプル

- メモリサンプル

- CPUサンプル
- Profilerタブに移動して、ソースメソッドに至るまでのオブジェクトのメモリ使用量を確認します。

詳細については、VisualVMのドキュメントを参照してください。
Dockerコンテナ
使用しているJVMのビルドやバージョンによっては、一部の機能がサポートされない場合があります(例えば、ibm-semeru-runtimes:open-17-jreビルドではヒープダンプが無効になっている場合があります)。Dockerでサポートされている機能の詳細については、Dockerコンテナのドキュメントを参照してください。
Java ExtendアプリでDockerコンテナを使用するには、以下の手順に従います。
- リモートモニタリング用にJMX接続を開きます。
- JVM引数を使用してJMX接続を有効にします。event-handlerアプリテンプレートの場合、
docker-compose.yamlのJAVA_OPTS環境変数を通じてJMX接続を有効にできます。- JAVA_OPTS=-Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=9010 -Dcom.sun.management.jmxremote.rmi.port=9010 -Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=127.0.0.1 - JMXポートを必ず公開してください。例えば、
docker-compose.yamlのPortsの下に- "9010:9010"を追加します。
- JVM引数を使用してJMX接続を有効にします。event-handlerアプリテンプレートの場合、
- docker composeを使用してアプリケーションを起動します。
- VisualVMを開き、新しいJMX Connectionを追加して、アドレス(例えば、ステップ1で設定した公開JMXポートの場合は
localhost:9010)を入力します。
Java Flight Recorder(JFR)とJDK Mission Control(JMC)
Java Flight Recorder(JFR)とJDK Mission Control(JMC)は、アプリケーション起動時からのイベントログを含む診断データの収集を支援します。これらのツールの詳細については、OracleのJFR Runtime Guideを参照してください。
商用ライセンスでの使用については、使用しているJDKディストリビューションを必ず確認してください。
Java Extendアプリでこれらのツールを使用するには、以下の手順に従います。
- リモートモニタリング用にJMX接続を開きます。
- JVM引数を使用してJMX接続を有効にします。event-handlerアプリテンプレートの場合、
docker-compose.yamlのJAVA_OPTS環境変数を通じてJMX接続を有効にできます。- JAVA_OPTS=-Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=9010 -Dcom.sun.management.jmxremote.rmi.port=9010 -Dcom.sun.management.jmxremote.local.only=false -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -Djava.rmi.server.hostname=127.0.0.1 - Java Extendアプリケーションの起動時にJFRで60秒間の記録を自動的に取得するには、次の環境変数を設定します。
- JAVA_OPTS=-XX:StartFlightRecording=filename=/tmp/startupProfiling.jfr,duration=60s,settings=profile - JMXポートを必ず公開してください。例えば、
docker-compose.yamlのPortsの下に- "9010:9010"を追加します。
- JVM引数を使用してJMX接続を有効にします。event-handlerアプリテンプレートの場合、
- JMCを開き、生成されたJFRファイルを探します。JFRファイルがローカルにない場合は、Dockerコンテナからコピーできます。
- 分析を開始します。オプションで、JFRに対してフライトレコーディングの開始と停止をオンデマンドで指示することもできます。

-
メモリのサンプル結果

-
メソッドプロファイリングのサンプル結果

-
Event Types TreeにおけるスレッドのCPU負荷のサンプル結果

参考資料
Oracleのトラブルシューティングガイドから、次の記事を読むことを推奨します。
- General Troubleshooting
- Debug JVM Issues (システムのクラッシュやハング、例外のトラブルシューティング)