次の例は、最終的な値型のローカル変数ではなく、最終的な参照型のフィールドを使用する、わずかに異なる例です。
public class MyClass {
public final MyOtherObject obj;
}
MyClass のインスタンスを作成するたびに、MyOtherObject インスタンスへの発信参照を作成することになり、GC はそのリンクをたどってライブ オブジェクトを探す必要があります。
JVM はマークスイープ GC アルゴリズムを使用します。これは、GC の「ルート」の場所にあるすべてのライブ参照 (現在のコール スタック内のすべてのオブジェクトなど) を調べる必要があります。各ライブ オブジェクトは、アライブとして「マーク」され、ライブ オブジェクトによって参照されるすべてのオブジェクトも、アライブとしてマークされます。
マーク フェーズの完了後、GC はヒープをスイープし、マークされていないすべてのオブジェクトのメモリを解放します (残りのライブ オブジェクトのメモリを圧縮します)。
また、Java ヒープ メモリが「若い世代」と「古い世代」に分割されていることを認識することも重要です。すべてのオブジェクトは、最初は若い世代 (「ナーサリ」と呼ばれることもあります) に割り当てられます。ほとんどのオブジェクトは存続期間が短いため、GC は若い世代から最近のガベージを解放することに積極的です。若い世代のコレクション サイクルを生き延びたオブジェクトは、処理頻度の低い古い世代 ("tenured 世代" とも呼ばれます) に移動されます。
だから、頭のてっぺんから、「いいえ、「最終」修飾子はGCがその負荷を軽減するのに役立ちません」と言うつもりです。
私の意見では、Java でメモリ管理を最適化するための最善の戦略は、偽の参照をできるだけ早く排除することです。使い終わったらすぐにオブジェクト参照に「null」を割り当てることで、これを行うことができます。
または、さらに良いのは、各宣言スコープのサイズを最小限に抑えることです。たとえば、1000 行のメソッドの先頭でオブジェクトを宣言し、そのオブジェクトがそのメソッドのスコープ (最後の右中括弧) を閉じるまで存続する場合、オブジェクトは実際よりもずっと長く存続する可能性があります。必要。
数十行程度のコードしかない小さなメソッドを使用すると、そのメソッド内で宣言されたオブジェクトはより迅速に範囲外になり、GC ははるかに効率的な方法でほとんどの作業を行うことができます。若い世代。絶対に必要でない限り、オブジェクトを古い世代に移動したくありません。