15

Java では、NIO ダイレクト バッファによって割り当てられたメモリはsun.misc.Cleaner、オブジェクトのファイナライズよりも効率的ないくつかの特別なファントム参照であるインスタンスで解放されます。

このクリーナー メカニズムは、JVM でダイレクト バッファー サブクラス専用にハードコーディングされていますか?それとも、カスタム コンポーネントでクリーナーを使用することは可能ですか (たとえば、カスタム ダイレクト バイト バッファーを作成します)?

ここでは、既存の nio ダイレクト バッファのクリーナー フィールドを取得することについては話していません。メモリを手動で解放することについても話していません。これは、直接メモリを割り当て、ガベージ コレクタ メカニズムによって効率的かつ自動的にクリーンアップする新しいクラスを作成することに関するものです。

4

3 に答える 3

17

API ドキュメント ( http://docs.oracle.com/javase/7/docs/api/java/lang/ref/package-summary.html ) を読むのにより多くの時間を費やした後、私はより詳細な答えを持っていると思います:

1) sun.misc.Cleaner を再利用して、独自のカスタム クラスを効率的にクリーンアップできます。提供されたファクトリ メソッドを呼び出してクリーナーを宣言します。

sun.misc.Cleaner.create(Object ob, Runnable cleanup);

しばらくの間、私はそれを適切に動作させることができませんでした。それは、クリーナーの実行可能なクリーンアップ コードを無名クラスとして定義するのに十分馬鹿げていたためです。ファントム到達可能」...

2) そのような効率的なクリーンアップを実装する他の方法はありません (ファントム参照の助けを借りても)

実際、参照ハンドラ スレッドは、sun.misc.Cleaner のインスタンスを特別な方法で処理します。

// Fast path for cleaners
if (r instanceof Cleaner) {
    ((Cleaner)r).clean();
    continue;
}

つまり、クリーンアップ コードは参照ハンドラ スレッドから直接呼び出されますが、標準的な使用法では、参照は参照ハンドラ スレッドによってキューに入れられ、別のアプリケーション スレッドによってキューから取り出されて処理される必要があります。

于 2013-07-17T12:00:51.350 に答える
2

パッケージ内の何かに依存するsun.miscと、それが消えてコードが壊れるリスクがあります。一部の部分は他の部分よりも安定していますが、多くの場合、それは悪い考えです (悪魔の擁護者: のメソッドの多くsun.misc.Unsafeは実際には JVM 組み込み関数によって実装されているため、ユーザーが作成した JNI コードよりも高速です)。

この場合、それは悪い考えだと思います:Cleanerによるクリーンアップの可能な実装の 1 つPhantomReferenceです。他にもあります。例についてはGoogle。さらに言えば、ファントム参照の使用方法の例として、それ自体のソース コードを見ることができます。Cleaner

オフヒープオブジェクトを参照するオンヒープ オブジェクトを使用する場合は、何らかのクリーンアップ ハンドラが必要になります。そうしないと、これらのヒープ上のオブジェクトが収集されるときに、真のメモリ リークが発生します。

于 2013-07-16T14:36:12.297 に答える