0

最近のプロジェクトで奇妙なメモリ リークの問題に直面しています。メッセージを「ハンドラー」コードに送信する「メイン」コードがあります。通信されると、ハンドラー コードは固定タスクを実行し、結果をディスクに書き込み、終了します。固定タスクは、別のクラスの特定の関数への呼び出しを介して実行されます。

この関数の実行中に、(予想どおり) ヒープ サイズが増加します。ただし、コードの完了時に、結果自体が多くのスペースを占めるべきではありません。handler の呼び出しが完了すると、メモリ フットプリントが小さくなることが予想されます。ただし、「トップ」は、ハンドラーがまだ大量のメモリ (RES) を消費していることを示しています。

スレッドによって消費されたヒープが確実に回収されるように、スレッドを終了するべきではありませんか? 関数の実行後に System.gc() 呼び出しを作成しようとしましたが、ガベージ コレクションは強制されません。

4

2 に答える 2

4

Hotspot JVM のガベージ コレクターは、"しぶしぶ" オペレーティング システムにメモリを返すだけです。アプリケーションは、再利用されたスペースにさらに多くのオブジェクトを作成する可能性が高いと想定されています。GC がメモリを返還する場合は、再度要求する必要があり、チャーンにより余分なシステム コールなどが発生します。

ただし、ヒープが不必要に大きいことに JVM が気付くと、ヒープ サイズが縮小され、最終的に JVM がメモリをいくらか戻す結果になる可能性があります。サイズ変更メカニズムについては、この Oracle Heap Tuning Parametersページに記載されています。


スレッドのスタックは Java ヒープ内に割り当てられないことにも注意してください。むしろ、通常はスレッドの開始時に OS から要求され、スレッドの終了時に解放される非ヒープ メモリ セグメントに存在します。

于 2013-10-29T13:54:14.610 に答える
2

スレッドが消費したヒープが確実に回収されるように、スレッドを終了するべきではありませんか? 関数の実行後に System.gc() 呼び出しを作成しようとしましたが、ガベージ コレクションは強制されません。

GC アクティビティをログに記録するために、いくつかの JVM フラグを追加してみてください。

-verbose:gc
-XX:+PrintGCTimeStamps
-XX:+PrintGCDetails

実際、スペースが再利用されていることがわかると思います。によって報告されるメモリ フットプリントにはtop、オブジェクトの割り当てに使用されたかどうかに関係なく、Java ヒープ用に予約された領域が含まれます。これらの数値を確実に使用して GC アクティビティを監視することはできません。

スレッドが終了しても、必ずしもガベージ コレクションがトリガーされるわけではありません。また、ガベージ コレクションによってプロセスのフットプリントが縮小することも期待できません。JVM は必要に応じてマネージド ヒープのサイズを増やしますが、必ずしも最初の機会に (またはおそらく) 縮小するとは限りません。プログラムのメモリ使用量が一度これらのレベルに達した場合、JVM はそれが再び発生しないと信じる理由がないため、システム メモリの負荷が非常に高くない限り、JVM がそのメモリをすぐに OS に解放することはほとんどありません (これまで)。

于 2013-10-29T13:53:38.780 に答える