sun.misc.CleanerまたはPhotomReferenceを使って、ヒープ外メモリの自動放出を実現します。
4219 ワード
以前のブログです。System.gc()-XX:+Dispable ExplicitGC起動パラメータとDirectByteBufferのメモリをリリースします。 記事の終わりに:java NIOパッケージといえば、sun.misc.CleanerとPhantomReferenceを通じてヒープ外メモリの自動放出を実現します。CleeanerとPhotomReferenceの使用を学び、自分でカプセル化してヒープ外メモリの自動放出を実現します。
sun.misc.CleanerはJDK内部で提供された非ヒープメモリ資源を解放するAPIである。JVMはメモリ資源を自動的にリリースしてくれるだけです。しかし、このようなシステムを通じて、他の資源を簡単に解放できるように調整機構を提供しています。まずCleeanerの使い方を見ます。
Clearer.create()は2つのパラメータが必要です。最初のパラメータ:監視が必要なメモリオブジェクト、2番目のパラメータ:プログラムリリースリソースのフィードバック。JVMがGCを行う時、私達が監視する対象が存在しないことを発見したら(Cleeanerの対象だけに引用されています。これは幽霊引用です。)、第二のパラメータRunnable.run()方法の論理を呼び出して、Runnable.run(この時はすでにヒープ外メモリを解放しました)を実行したら、JVMは自動的にヒープメモリの中の監視対象を釈放します。sun.misc.Cleanerを使うのは簡単です。
次に私達はsun.misc.Cleanerを使わない場合、どうやって資源を放出しますか?
その後、私たちはバックグランドでCleeaner Threadスレッドを開いて、絶えずポーリング引用キューを発見したら、キューの中にデータがあります。
対応するRunnableを探し出して、そのrun方法を呼び出して、ヒープの対象のheappObjectの中で引用するヒープ外メモリを釈放します。テストコードは以下の通りです。
sun.misc.CleanerはJDK内部で提供された非ヒープメモリ資源を解放するAPIである。JVMはメモリ資源を自動的にリリースしてくれるだけです。しかし、このようなシステムを通じて、他の資源を簡単に解放できるように調整機構を提供しています。まずCleeanerの使い方を見ます。
package direct;
public class FreeMemoryTask implements Runnable
{
private long address = 0;
public FreeMemoryTask(long address)
{
this.address = address;
}
@Override
public void run()
{
System.out.println("runing FreeMemoryTask");
if (address == 0)
{
System.out.println("already released");
} else
{
GetUsafeInstance.getUnsafeInstance().freeMemory(address);
}
}
}
これはRunnableインターフェースの種類を実現しました。機能はヒープ外メモリを解放することです。これは私たちがしなければならないことです。JVMは私たちを手伝ってくれません。public class ObjectInHeapUseCleaner
{
private long address = 0;
public ObjectInHeapUseCleaner()
{
address = GetUsafeInstance.getUnsafeInstance().allocateMemory(
2 * 1024 * 1024);
}
public static void main(String[] args)
{
while (true)
{
System.gc();
ObjectInHeapUseCleaner heap = new ObjectInHeapUseCleaner();
// heap , FreeMemoryTask
Cleaner.create(heap, new FreeMemoryTask(heap.address));
}
}
}
このコードを実行すると、プログラムは正常に動作し、OOMは発生しません。Clearer.create()は2つのパラメータが必要です。最初のパラメータ:監視が必要なメモリオブジェクト、2番目のパラメータ:プログラムリリースリソースのフィードバック。JVMがGCを行う時、私達が監視する対象が存在しないことを発見したら(Cleeanerの対象だけに引用されています。これは幽霊引用です。)、第二のパラメータRunnable.run()方法の論理を呼び出して、Runnable.run(この時はすでにヒープ外メモリを解放しました)を実行したら、JVMは自動的にヒープメモリの中の監視対象を釈放します。sun.misc.Cleanerを使うのは簡単です。
次に私達はsun.misc.Cleanerを使わない場合、どうやって資源を放出しますか?
import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.HashMap;
import java.util.Map;
public class MyOwnCleaner
{
private static ReferenceQueue
ここではPhotomReferenceとReferenceQueを使っていますが、これはJVM内部の対象破壊メカニズムです。山の中の対象が存在しない場合は、強い引用があり、幽霊引用のみが存在する場合、JVMは自動的にこの対象の幽霊を関連する引用列に引用する。private static ReferenceQueue refQueue = new ReferenceQueue();
これは列を引用して、JVMは自動的にPhotomReferenceを引用して列の中に入ります。つまり、この列をポーリングすれば、どのオブジェクトがJVMによって回収されるかが分かります。public static void clear(Object heapObject, Runnable task)
{
// heapObject ,reference JVM
// reference
PhantomReference reference = new PhantomReference(
heapObject, refQueue);
taskMap.put(reference, task);
}
このコードは、かなりのもので、私たちはヒープの中のオブジェクトに監視カメラを追加しました。taskMapは幽霊引用と対応するコード回収ロジックを記録しています。その後、私たちはバックグランドでCleeaner Threadスレッドを開いて、絶えずポーリング引用キューを発見したら、キューの中にデータがあります。
対応するRunnableを探し出して、そのrun方法を呼び出して、ヒープの対象のheappObjectの中で引用するヒープ外メモリを釈放します。テストコードは以下の通りです。
public class Test
{
private long address = 0;
public Test()
{
address = GetUsafeInstance.getUnsafeInstance().allocateMemory(
2 * 1024 * 1024);
}
public static void main(String[] args)
{
while (true)
{
Test heap = new Test();
MyOwnCleaner.clear(heap, new FreeMemoryTask(heap.address));
System.gc();
}
}
}
テストコードを実行しても、OOMは報告されません。つまり、スタック外メモリの自動放出が正しく実現されました。