ガベージコレクターが実行されてメモリを解放すると、このメモリはOSに戻りますか、それともプロセスの一部として保持されます。メモリが実際にOSに解放されることはなく、同じプロセスで再利用されるメモリ領域/プールの一部として保持されるという強い印象を受けました。
その結果、プロセスの実際のメモリは決して減少しません。 記事 このことを思い出し、JavaのランタイムはC/C++で書かれているので、同じことが当てはまると思いますか?
更新
私の質問はJavaについてです。 Javaの割り当て/割り当て解除は何らかの形のmalloc/deleteを使用してJREによって行われると想定しているため、C/C++について言及しています。
HotSpot JVM はメモリをOSに解放しますが、ヒープのサイズ変更は高価であり、そのヒープが必要になった場合は再び必要になるため、しぶしぶそうです。
-XX:GCTimeRatio=19 -XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=30
を設定することでより積極的にすることができます。これにより、GCサイクル後の割り当て済みで未使用のヒープメモリの収集と制限にCPU時間を費やすことができます。
コンカレントコレクタを使用していると仮定すると、Nで-XX:InitiatingHeapOccupancyPercent=N
を低い値に設定して、GCでコンカレントコレクションをほぼ連続的に実行できるようになります。この一般的には良いアイデアではありませんが、多くの予備のCPUコアを備えているがメモリが不足している一部のタイプのマシンでは意味があります。
デフォルトの休止時間目標(CMSまたはG1)でコレクターを使用している場合は、その目標を緩和してコレクターの制約を減らすか、パラレルコレクターを切り替えて休止時間よりもフットプリントを優先させることもできます。
さらにJava 9 -XX:-ShrinkHeapInSteps
オプションを使用すると、前の2つのオプションによる縮小をより積極的に適用できます。 関連するOpenJDKバグ 。
縮小機能と動作は、選択したガベージコレクターに依存することに注意してください。たとえば、G1はjdk8u20で ヒープの中央に未使用のチャンクを返す の能力しか得られませんでしたが、ZGC jdk13でdid であり、イプシロンコレクターはおそらくそうなりません。
したがって、ヒープの縮小が必要な場合は、特定のJVMバージョンとGC構成についてテストする必要があります。
PrintAdaptiveSizePolicy
を使用したGCロギングも洞察を提供します。 JVMが、若い世代がいくつかの目標を達成するためにより多くのメモリを使用しようとするとき。
また、OpenJDK 12に含まれる JEP 346 があります。これはG1PeriodicGCInterval
オプションを使用してG1GCのプロンプトメモリリリースを導入しますが、CPUをいくらか追加します。 Shenandoah および OpenJ9 VM の同様の機能にも言及しています。
JVMは特定の状況下でメモリを解放しますが、(パフォーマンス上の理由から)これは、メモリがガベージコレクションされるたびに発生しません。また、JVM、OS、ガベージコレクタなどにも依存します。JConsole、VisualVM、または別のプロファイラを使用して、アプリのメモリ消費を監視できます。
こちらもご覧ください 関連バグレポート
G1コレクターを使用してSystem.gc()を時々呼び出すと(1分に1回)、Javaは確実にヒープを縮小し、OSにメモリを返します。
ガベージコレクターを手動で呼び出すというアイデアに言及するときでも口の中で泡立つ人もいますが、信頼できるヒープコンパクションが必要な場合はそうする必要があります。
これらのオプションを、非常にコンパクトな常駐プロセスサイズの上記の提案と組み合わせて使用することをお勧めします。
-XX:+UseG1GC -XX:MaxHeapFreeRatio=30 -XX:MinHeapFreeRatio=10
クラスを動的にロードおよびアンロードする大きなアプリケーション(JavaベースのゲストOS全体)でこれらのオプションを数か月間毎日使用しており、Javaプロセスはほとんど常に400〜800 MBのままです。
編集:JDK 12にはG1コレクターがあります OSにメモリを返す (System.gcを呼び出さずに)「アプリケーションがアイドル状態のとき」。後者の用語はサーバーアプリケーションに対して定義されているようですが、おそらくデスクトップでも機能し、カスタマイズできるようになるでしょう。
この記事 here はJavaでGCがどのように機能するかを説明しています。通常、メモリはJavaプロセス用に保持され、一部のGCのみがシステムに解放します(リクエストに応じて)。ただし、Javaプロセスで使用されるメモリは、Xmxオプションで定義された上限があるため(通常は256mですが、OS /マシンに依存していると思います)、無限に増加することはありません。