私は現在Java=アプリケーションに取り組んでおり、そのメモリ使用量を最適化するために取り組んでいます。私が知る限り、適切なガベージコレクションのガイドラインに従っています。しかし、ヒープは必要ありませんが、最大サイズのままです。
私のプログラムは、コンピュータが人によって使用されていないときに、1時間に1回、リソースを集中的に使用するタスクを実行しています。このタスクは適切なメモリチャンクを使用しますが、タスクが完了するとすぐにすべてを解放します。 NetBeansプロファイラにより、メモリ使用量は次のようになることがわかります。
使用していないときは、ヒープ領域をすべてOSに戻したいのですが。プログラムが少なくとももう1時間は何もしないのに、私がそれを独り占めする理由はありません。
これは可能ですか?ありがとう。
あなたはおそらく_-XX:MaxHeapFreeRatio
_をいじることができます-これは、GCがヒープを縮小する前に解放されるヒープの最大パーセンテージ(デフォルトは70)です。多分それを少し低く(40または50?)設定してからSystem.gc()
を使用すると、望ましい動作が得られるまでに時間がかかる場合があります。
これを強制的に実行する方法はありませんが、JVMに強制的に実行させることはできますが、必要に応じてメモリを削除することはできません。そして、上記はヒープを縮小するかもしれませんが、そのメモリは必ずしもOSに直接戻されるとは限りません(ただし、JVMの最近の実装ではそうです)。
ショートバージョン:はい、できます。
ロングバージョン:
ほとんどのアプリケーションでは、JVMのデフォルトで問題ありません。 JVMは、アプリケーションが限られた期間だけ実行されることを期待しているようです。したがって、それ自体ではメモリを解放しないようです。
JVMがガベージコレクションを実行する方法とタイミングを決定できるようにするには、次のパラメーターを指定する必要があります。
-Xms
_最小ヒープサイズを指定します–Xmx
_最大ヒープサイズを指定しますサーバーアプリケーションの場合:_-server
_を追加します。
上記のパラメーターでは不十分な場合、ガベージコレクションに関するJVMの動作に影響を与えることができます。
最初に、System.gc()
を使用して、ガベージコレクションが意味があると思われる場合にVMを通知できます。次に、JVMが使用するガベージコレクターを指定できます。
シリアルGC
コマンドラインパラメーター:_-XX:+UseSerialGC
_
アプリケーションを停止し、GCを実行します。
並列GC
コマンドラインパラメーター:_-XX:+UseParallelGC -XX:ParallelGCThreads=value
_
アプリケーションと並行してマイナーコレクションを実行します。 メジャーコレクションに必要な時間を短縮しますが、別のスレッドを使用します。
並列圧縮GC
コマンドラインパラメーター:_-XX:+UseParallelOldGC
_
アプリケーションと並行してメジャーコレクションを実行します。より多くのCPUリソースを使用し、メモリ使用量を減らします。
CMS GC
コマンドラインパラメーター:_-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=value -XX:+UseCMSInitiatingOccupancyOnly
_
より小さなコレクションを実行し、Serial GCより頻繁に実行するため、アプリケーションの中断/停止を制限します。
G1
コマンドラインパラメーター:_-XX:+UnlockExperimentalVMOptions -XX:+UseG1GC
_
試験運用版(少なくともJava 1.6):アプリケーションが1秒以上停止しないようにしようとします。
最適化なしのPlay Framework Webアプリケーションのメモリ使用量: ご覧のとおり、ヒープ領域はかなり多く使用されており、使用された領域は定期的に解放されます。
この場合、パラメータのみを使用した最適化は効果がありませんでした。かなり多くのメモリを使用するいくつかのスケジュールされたタスクがありました。この場合、メモリを集中的に使用する操作の後に__CMS GC
_をSystem.gc()
と組み合わせて使用することにより、最高のパフォーマンスが得られました。その結果、WebAppのメモリ使用量は1.8 GBから約400〜500 MBに削減されました。
メモリがどのようにJVMによって解放され、実際にOSに返されるかを示すVisualVMの別のスクリーンショットを次に示します。
注:メモリを消費するスケジュールされたタスクは特定の時間にのみ起動されるため、コードでSystem.gc()
ではなくVisualVMの[Perform GC]ボタンを使用してGCを実行しましたVisualVMでキャプチャするのは困難です。
JVMはそのようには機能しません。 OSに戻すことはできません。
これが4年前に作成されてから数人が述べたように、JVMに適切なGC設定を指定すると、メモリをOSに戻すことができます。
Javaは秘密を厳守する:-Xincgcこれはパフォーマンスに影響を与えますが、常にそれほど影響を与えるわけではありません。時々、それはあなたがしていることに依存します。インクリメンタルガベージコレクターは、メモリをシステムに適切に戻します。
1つの可能性として、バックグラウンドJavaアプリケーションがタスクを実行するために毎時間外部jvmインスタンスを起動するようにします。これにより、元のjvmアプリケーションのみがタスク間で実行されます。
アプリが非アクティブな期間中に静止している場合、OSがそれらのページをスワップアウトして、物理メモリへのプレッシャーを軽減する可能性があります。
http://www.linuxvox.com/2009/10/what-is-the-linux-kernel-parameter-vm-swappiness/
Java 12は、G1GCを使用してこの機能をサポートしています。
JEP 346:G1から未使用のコミットされたメモリを即座に返します。
アイドル時にオペレーティングシステムにJavaヒープメモリを自動的に返すようにG1ガベージコレクターを拡張します。
https://openjdk.Java.net/jeps/346
Java 13はzgcを使用してこの機能をサポートしています
JEP 351:ZGC:Uncommit Unused Memory
ZGCは現在、メモリが長期間使用されていない場合でも、コミットを解除してメモリをオペレーティングシステムに返しません。この動作は、すべてのタイプのアプリケーションと環境、特にメモリフットプリントが問題となる環境に最適ではありません。例:リソースが使用によって支払われるコンテナ環境。
アプリケーションが長期間アイドル状態で、他の多くのアプリケーションとリソースを共有または競合している環境。
アプリケーションの実行中に、ヒープ領域の要件が大きく異なる場合があります。たとえば、起動時に必要なヒープは、安定した状態の実行中に後で必要になるヒープよりも大きい場合があります。