この項では、ガベージ・コレクションに影響するその他の状況について説明します。
一部のアプリケーションは、ファイナライズと弱参照、ソフト参照またはファントム参照を使用してガベージ・コレクションと相互作用します。
ただし、ファイナライズの使用は推奨されません。 セキュリティ、パフォーマンスおよび信頼性の問題が発生する可能性があります。 たとえば、ファイナライズによってファイル記述子を閉じると、外部リソース(記述子)がガベージ・コレクションの機敏性に依存するようになります。
クラスはファイナライザを宣言できます - メソッドprotected void finalize() - 基礎となるリソースを解放する本文。 GCは、GCがオブジェクトのメモリーを回収する前に呼び出される、到達不能オブジェクトのファイナライザをスケジュールします。
オブジェクトは到達不能になるため、GCルートからオブジェクトへのパスがない場合、ガベージ・コレクションの対象になります。 (到達可能性の詳細は、「参照オブジェクト・タイプ」を参照してください。) GCルートには、アクティブなスレッドからの参照および内部JVM参照が含まれます。これらは、オブジェクトをメモリーに保持する参照です。
ファイナライズ可能なオブジェクトがシステムで構築されているかどうかを確認するには、「Java Platform, Standard Editionトラブルシューティング・ガイド」の「ファイナライズ保留中のオブジェクトのモニター」を参照してください。 また、次のいずれかのツールを使用することもできます:
jcmd:
次のコマンドを実行して、Javaファイナライズ・キューに関する情報を出力します。値<pid>はJVMのPIDです:
jcmd <pid> GC.finalizer_info
ファイナライズを回避するには、try-with-resources文を使用します。 これは、1つ以上のリソースを宣言するtry文です。 リソースは、プログラムでの使用が終わったら閉じる必要があるオブジェクトです。 try-with-resources文は、1つ以上の例外が発生した場合でも、各リソースがコード・ブロックの最後に閉じられるようにします。 詳細は、Try-with-resources文に関する項を参照してください。
3つの参照オブジェクト・タイプがあります: SoftReference、WeakReferenceおよびPhantomReference。 参照オブジェクト・タイプはそれぞれ異なるレベルの到達可能性に対応します。 次に、オブジェクトのライフサイクルを反映する、最強から最弱までの様々な到達可能性レベルを示します:
各参照オブジェクト型は、「レ・フリー」と呼ばれる特定のオブジェクトへの単一の参照をカプセル化します。 参照オブジェクトは、リファレントをクリアするためのメソッドを提供します。
参照オブジェクト・インスタンスの最も一般的な使用方法は次のとおりです:
ReferenceQueueクラスとの組合せ)に達したときに、なんらかのアクションを実行する場合アプリケーションがガベージ・コレクションと相互作用できるもう1つの方法は、System.gc()をコールして、すべてのガベージ・コレクションを明示的に呼び出すやり方です。 これを行うと、必要ない場合(たとえば、マイナー・コレクションで十分な場合)でもメジャー・コレクションの実行が強制されるので、通常は使用しないことをお薦めします。 明示的なガベージ・コレクションによるパフォーマンスへの影響を測定するには、フラグ-XX:+DisableExplicitGCを使用してVMにSystem.gc()のコールを無視させ、明示的なガベージ・コレクションを無効にします。
明示的なガベージ・コレクションが最もよく使用される例の1つが、リモート・メソッド呼出し(RMI)の分散ガベージ・コレクション(DGC)です。 RMIを使用するアプリケーションは、他の仮想マシンのオブジェクトを参照します。 これらの分散アプリケーションでは、ローカル・ヒープのガベージ・コレクションを時々呼び出さないとガベージを収集できないので、RMIがフル・コレクションを定期的に実行します。 これらのコレクションの実行間隔はプロパティで制御できます(次の例を参照)。
java -Dsun.rmi.dgc.client.gcInterval=3600000
-Dsun.rmi.dgc.server.gcInterval=3600000 ...
この例では、明示的なガベージ・コレクションの実行間隔をデフォルトの1回/分ではなく、1回/時間に指定します。 ただし、これでも一部のオブジェクトが回収されるまでに長時間かかる場合があります。 DGCのタイムリな処理に上限を設定する必要なければ、これらのプロパティの値をLong.MAX_VALUEまで引き上げ、明示的なコレクションの時間間隔を事実上無限大にすることができます。
サーバー仮想マシンでは、ソフト参照がクライアント仮想マシンよりも長くライブに保たれます。 クリア間隔を制御するには、コマンド行オプション-XX:SoftRefLRUPolicyMSPerMB=<N>を使用して、ソフト参照を(強到達可能ではなくなってから)ライブに保つ期間を、ヒープ内の空き領域1MB当たりのミリ秒(ms)で指定します。 デフォルト値は1000ms/MBで、これは、(オブジェクトへの最後の強参照が収集された後の)ソフト参照がヒープ内の空き領域1MB当たり1秒の寿命であることを意味します。 ソフト参照は、散発的に発生するガベージ・コレクション時にのみクリアされるので、これは概算値です。
JavaクラスにはJava Hotspot VM内の内部表現があり、それはクラス・メタデータと呼ばれます。 以前のリリースのJava Hotspot VMで、クラス・メタデータはPermanentと呼ばれる永続的世代に割り当てられていました。 JDK 8では、永続的(Permanent)世代が削除され、クラス・メタデータがネイティブ・メモリーに割り当てられます。 クラス・メタデータに使用できるネイティブ・メモリーの容量はデフォルトで無制限です。 クラス・メタデータに使用するネイティブ・メモリーの容量に上限を設定するには、オプションMaxMetaspaceSizeを使用します。
Java Hotspot VMではメタデータ用の領域を明示的に管理します。 OSから領域が要求され、その領域がチャンクに分割されます。 そのチャンクからクラス・ローダーがメタデータに領域を割り当てます(チャンクは特定のクラス・ローダーにバインドされます)。 クラス・ローダーのクラスがアンロードされると、そのチャンクは再利用に回されるか、OSに返されます。 メタデータは、mallocではなくmmapによって割り当てられた領域を使用します。
UseCompressedOopsが有効でUseCompressedClassesPointersが使用されている場合、クラス・メタデータには、論理的に異なる2つの領域のネイティブ・メモリーが使用されます。 UseCompressedClassPointersでは、UseCompressedOopsのJavaオブジェクト参照と同様に、32ビット・オフセットを使用してクラス・ポインタを64ビット・プロセスで表現します。 このような圧縮クラス・ポインタにリージョンが割り当てられます(32ビット・オフセット)。 リージョンのサイズはCompressedClassSpaceSizeで設定でき、デフォルトは1ギガバイト(GB)です。 圧縮クラス・ポインタの領域は、初期化時にmmapによって割り当てられた領域として確保され、必要に応じてコミットされます。 MaxMetaspaceSizeは、コミットされた圧縮クラスの領域と他のクラス・メタデータの領域の合計に適用されます。
クラス・メタデータは対応するJavaクラスのアンロード時に割当て解除されます。 Javaクラスはガベージ・コレクションに伴ってアンロードされるので、クラスのアンロードとクラス・メタデータの割当て解除を行うためにガベージ・コレクションが誘発される場合があります。 クラス・メタデータ用にコミットされた領域が一定のレベル(最高水位標)に到達すると、ガベージ・コレクションが発生します。 ガベージ・コレクション後、クラス・メタデータから解放された領域量に応じて、最高水位標が上げられたり、下げられたりすることがあります。 別のガベージ・コレクションがすぐに発生しないように、最高水位標は上げられます。 最高水位標の初期値は、コマンド行オプションMetaspaceSizeの値に設定されます。 MaxMetaspaceFreeRatioオプションとMinMetaspaceFreeRatioオプションを基に、これを上げ/下げします。 クラス・メタデータで使用可能なコミットされた領域(クラス・メタデータ用にコミットされた総領域の割合)がMaxMetaspaceFreeRatioより大きいと、最高水位標は下げられます。 これがMinMetaspaceFreeRatioより低いと、最高水位標は上げられます。
クラス・メタデータによるガベージ・コレクションの早期誘発を避けるには、オプションMetaspaceSizeに高めの値を指定します。 アプリケーションに割り当てられるクラス・メタデータの容量はアプリケーションに依存するので、MetaspaceSizeの選択に一般的なガイドラインはありません。 MetaspaceSizeのデフォルト・サイズは、12MBから約20MBの範囲でプラットフォームに依存します。
メタデータに使用される領域に関する情報はヒープの出力に含まれます。 典型的な出力を例11-1「典型的なヒープ出力」に示します。
Heap
PSYoungGen total 10752K, used 4419K
[0xffffffff6ac00000, 0xffffffff6b800000, 0xffffffff6b800000)
eden space 9216K, 47% used
[0xffffffff6ac00000,0xffffffff6b050d68,0xffffffff6b500000)
from space 1536K, 0% used
[0xffffffff6b680000,0xffffffff6b680000,0xffffffff6b800000)
to space 1536K, 0% used
[0xffffffff6b500000,0xffffffff6b500000,0xffffffff6b680000)
ParOldGen total 20480K, used 20011K
[0xffffffff69800000, 0xffffffff6ac00000, 0xffffffff6ac00000)
object space 20480K, 97% used
[0xffffffff69800000,0xffffffff6ab8add8,0xffffffff6ac00000)
Metaspace used 2425K, capacity 4498K, committed 4864K, reserved 1056768K
class space used 262K, capacity 386K, committed 512K, reserved 1048576K
「Metaspace」で始まる行のused値は、ロード済クラスが使用している領域量です。 capacity値は、現在割り当てられているチャンク内のメタデータで使用可能な領域です。 committed値は、チャンクの使用可能な領域量です。 reserved値は、メタデータ用に確保された(必ずしもコミットされているとはかぎらない)領域量です。 「class space」で始まる行には、圧縮クラス・ポインタのメタデータの対応する値が含まれています。