[再現] Javaの4つの参照関係

免責事項:この記事は、記事を転載再現され、元のソースリンクの量を変更することなどがこの文は再び再現してください。
オリジナルリンク:https://blog.csdn.net/u013256816/article/details/50907595

弱いソフト強い参照を、および参照は虚数引用し、定義されたパッケージにこれら四つの参考文献:Javaは参照の4つのレベルを提供java.lang.ref以下:

Javaソースは、関係の位置の4種類に引用しました

1つの強い参照(最終参照)

強い参照は次のように、プログラムコード内の罹患率を指すObject obj = new Object()限り強い参照があるように、ガベージコレクタは、これらのオブジェクトが参照されている回復する行くことはありません、参照。

強い参照は、以下の3つの特徴があります。

1)強い参照を直接標的することによってアクセスすることができる;
2)強力な基準点はいつでもオブジェクトをロックするために、システムは--jvmむしろ例外OOMが強い参照オブジェクトポイントを回復しないスローする回収されない;
3)強い参照してもよいですそのようなリストを失った後、新しいリストが出てオブジェクトを追加するなどの原因となるメモリリークは、その内部オブジェクトにアクセスすることができない、回復しているが、現象は回復されません。

定義されているすべてのFinalReferenceクラスは次のとおりです。

package java.lang.ref;
/**
 * Final references, used to implement finalization
 */
class FinalReference<T> extends Reference<T> {
    public FinalReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }
}

FinalReferenceのみコンストラクタ:強い参照指定されたオブジェクトと参照キュー構造を参照する方法。

2つのソフト参照(ソフト参照)

ソフト参照は必ずしも必要ではないだけでなく、オブジェクトと、いくつかを記述するために使用されています。オブジェクトに関連付けられたソフト参照、十分なメモリ、ガベージコレクタがオブジェクトを再利用しない場合は、
メモリが十分でない場合、彼らはこれらのオブジェクトを回復します。

システムが行われるOutOfMemoryErrorJVMは、リカバリ範囲として記載されているオブジェクト、および第2の回収に関連したソフト参照になり、前に。場合は、メモリの回復はまだ十分ではありませんした後、システムがスローされますOutOfMemoryError

ソフトSoftReferenceクラス参照を達成するために最初からJDK 1.2を提供:キャッシュメモリに敏感なを達成するために組み合わせて使用​​されるキューへの参照(ReferenceQueue) - ソフト参照オブジェクトがガベージコレクト参照されている場合は、JVMは、ソフト参照を配置します参照に関連付けられたキューに加えました。

2.1ケース1:ガベージコレクションソフト参照

package com.healchow.java.detail;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;

public class SoftRefTest {
    private static ReferenceQueue<MyObject> softQueue = new ReferenceQueue<>();

    private static class MyObject {
        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            System.out.println("MyObject's finalize called");
        }
        @Override
        public String toString() {
            return "I am MyObject";
        }
    }

    private static class CheckRefQueue implements Runnable {
        Reference<MyObject> obj = null;
        @Override
        public void run() {
            try {
                obj = (Reference<MyObject>) softQueue.remove();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (obj != null) {
                System.out.println("Object for SoftReference is " + obj.get());
            }
        }
    }
    
    public static void main(String[] args) {
        MyObject obj = new MyObject();
        SoftReference<MyObject> softRef = new SoftReference<>(obj, softQueue);
        new Thread(new CheckRefQueue()).start();

        // 删除强引用, 否则obj不会被回收
        obj = null;
        System.gc();
        System.out.println("After GC: Soft Get = " + softRef.get());
        System.out.println("尝试分配大块内存...");
        byte[] b = new byte[5 * 1024 * 725];
        System.out.println("After new byte[]: Soft Get = " + softRef.get());
        System.gc();
    }
}

(1)試験方法1:

:試験方法VM主要パラメータ実行時に設定-Xmx5M、次のように5メガバイト、業績のプログラムのJavaヒープの最大値を指定します。

After GC: Soft Get = I am MyObject
尝试分配大块内存...
After new byte[]: Soft Get = I am MyObject
MyObject's finalize called
Object for SoftReference is null

ケースコード説明:

①まず、オブジェクトMyObjectにを作成し、オブジェクト変数に割り当てられ、強い参照を構成します。

②次に、この構築物SoftReferenceソフト参照オブジェクトMyObjectにsoftRefを使用し、softQueue参照キューに登録 - リサイクルすることsoftRefとき、それはsoftQueueキューに追加されます。

③設定obj = nullMyObjectにオブジェクトへの強い参照を削除してシステムの参照のみソフト参照。

④軟らかい基準MyObjectにオブジェクトを取得するには、Get()メソッドによって引用コールGCを示し、オブジェクトがよく、メモリ条件でGCは、ソフト参照オブジェクトを回復しないであろうことを示し、回収されることが見出されませんでした。

⑤次に大きいヒープスペースを要求し5*1024*725、このGC後(作業がスムーズにガベージコレクションを進めることができるように複数回調整する、滑らか終了スレッド)、この操作は、GCの新しいラウンドで得られ、神経系ヒープメモリの使用量を行います、softRef.get()MyObjectにオブジェクトを返すことはないが、nullを返す- 。それが回収されたときにストレスの多い状況では、システム・メモリの内容は、ソフト参照は、ソフト参照をリサイクルされ、それは、キュー要素を参照して、キュー参照、登録、この時間に加算され、複数のスレッドが開かないsoftQueue.remove()もはやブロックされているので、プログラムが正常終了です。

ケース再び大きな変化上記の配列は、例えば場合は5*1024*1024、OOM例外がスローされます。

After GC: Soft Get = I am MyObject
尝试分配大块内存...
MyObject's finalize called
Exception in thread "main" Object for SoftReference is null
java.lang.OutOfMemoryError: Java heap space
    at com.healchow.java.detail.SoftRefTest.main(SoftRefTest.java:56)

(2)試験方法2:

試験方法VMの主なパラメータを実行するときに設定します。-Xmx5M -XX:PrintGCDetailsログ情報は、(GCログは、「Javaヒープメモリhttp://blog.csdn.net/u013256816/article/details/50764532」で見ることができる)のための営業成績をGCを印刷します:

[GC (Allocation Failure) [PSYoungGen: 1024K->480K(1536K)] 1024K->480K(5632K), 0.0013139 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (System.gc()) [PSYoungGen: 1383K->480K(1536K)] 1383K->544K(5632K), 0.0011186 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System.gc()) [PSYoungGen: 480K->0K(1536K)] [ParOldGen: 64K->504K(4096K)] 544K->504K(5632K), [Metaspace: 3316K->3316K(1056768K)], 0.0044642 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
After GC: Soft Get = I am MyObject
尝试分配大块内存...
[GC (Allocation Failure) [PSYoungGen: 38K->64K(1536K)] 542K->568K(5632K), 0.0009263 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 64K->32K(1536K)] 568K->536K(5632K), 0.0011345 secs] [Times: user=0.00 sys=0.00, real=0.01 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 32K->0K(1536K)] [ParOldGen: 504K->504K(4096K)] 536K->504K(5632K), [Metaspace: 3317K->3317K(1056768K)], 0.0038031 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] 504K->504K(5632K), 0.0007999 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (Allocation Failure) [PSYoungGen: 0K->0K(1536K)] [ParOldGen: 504K->486K(4096K)] 504K->486K(5632K), [Metaspace: 3317K->3317K(1056768K)], 0.0037241 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
MyObject's finalize called
Object for SoftReference is null
After new byte[]: Soft Get = null
[Full GC (System.gc()) [PSYoungGen: 59K->0K(1536K)] [ParOldGen: 4086K->4083K(4096K)] 4145K->4083K(5632K), [Metaspace: 3317K->3317K(1056768K)], 0.0036086 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
Heap
 PSYoungGen      total 1536K, used 10K [0x00000007bfe00000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 1024K, 1% used [0x00000007bfe00000,0x00000007bfe02a68,0x00000007bff00000)
  from space 512K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007bff80000)
  to   space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
 ParOldGen       total 4096K, used 4083K [0x00000007bfa00000, 0x00000007bfe00000, 0x00000007bfe00000)
  object space 4096K, 99% used [0x00000007bfa00000,0x00000007bfdfcfc0,0x00000007bfe00000)
 Metaspace       used 3324K, capacity 4564K, committed 4864K, reserved 1056768K
  class space    used 366K, capacity 388K, committed 512K, reserved 1048576K

2.2ケース2:ソフト参照のキャッシュを使用します

public class BitMapManager {
    private Map<String, SoftReference<Bitmap>> imageCache = new HashMap<>();

    // 保存Bitmap的软引用到HashMap
    public void saveBitmapToCache(String path) {
        // 强引用的Bitmap对象
        Bitmap bitmap = BitmapFactory.decodeFile(path);
        // 软引用的Bitmap对象
        SoftReference<Bitmap> softBitmap = new SoftReference<Bitmap>(bitmap);
        // 添加该对象到Map中使其缓存
        imageCache.put(path, softBitmap);
        // 使用完后手动将位图对象置null
        bitmap = null;
    }

    public Bitmap getBitmapByPath(String path) {
        // 从缓存中取软引用的Bitmap对象
        SoftReference<Bitmap> softBitmap = imageCache.get(path);
        // 判断是否存在软引用
        if (softBitmap == null) {
            return null;
        }
        // 取出Bitmap对象,如果由于内存不足Bitmap被回收,将取得空
        Bitmap bitmap = softBitmap.get();
        return bitmap;
    }
}

ソフト参照の2.3アプリケーションシナリオ

ソフト参照は、主にファイル操作を読み取るために必要なハードウェアが遅いので、ほとんどのAndroidアプリ。写真をたくさん使います。頻繁にAndroidのシステムで使用されるメモリに敏感なキャッシュに使用するので、キャッシュされたあなたのイメージを置くことを検討し、必要がありますメモリから直接読み込むとき。

比較的大きなメモリ空間に画像キャッシュの多くは、簡単にOutOfMemoryErrorを発生することがあり、絵を占めていたが、その後、我々はこの問題を回避するために、ソフト参照技術の使用を考慮することができます。

SoftReferenceは、OOMの問題を解決することができます。各オブジェクトがインスタンス化され、オブジェクトがキャッシュの形で保存され、あなたがもう一度オブジェクトを呼び出すとき、あなたは直接ソフト参照のことで、ソフト参照を介してすることができますget()メソッドオブジェクトを取得したリソースデータ。ときOOMメモリが開催されます、GCはすぐにOOMが発生しないようにするすべてのソフト参照を削除します。

3つの弱参照(弱い参照)

非必須オブジェクトを記述するために使用される弱参照、その強度が弱い、弱参照オブジェクトは、次のガベージコレクションが発生するまで生き残るためにのみ関連付けられている場合、ガベージコレクタジョブに関係なく、ソフト十分により、現在のメモリを参照するかどうかの、弱参照オブジェクトがガベージコレクトされると関連する失われただけ弱参照オブジェクトを回収するには、キュー登録基準に追加されます。

私たちは、わずかケース1の上にコードを変更します。

package com.healchow.java.detail;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;

public class WeakRefTest {
    private static ReferenceQueue<MyObject> weakQueue = new ReferenceQueue<>();

    private static class MyObject {
        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            System.out.println("MyObject's finalize called");
        }
        @Override
        public String toString() {
            return "I am MyObject";
        }
    }

    private static class CheckRefQueue implements Runnable {
        Reference<MyObject> obj = null;
        @Override
        public void run() {
            try {
                obj = (Reference<MyObject>)weakQueue.remove();
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(obj != null) {
                System.out.println("删除的弱引用为: " + obj);
                System.out.println("获取弱引用的对象 obj.get() 为: " + obj.get());
            }
        }
    }

    public static void main(String[] args) {
        MyObject object = new MyObject();
        Reference<MyObject> weakRef = new WeakReference<>(object,weakQueue);
        System.out.println("创建的弱引用为: " + weakRef);
        new Thread(new CheckRefQueue()).start();

        object = null;
        System.out.println("Before GC: Weak Get = " + weakRef.get());
        System.gc();
        System.out.println("After GC: Weak Get = " + weakRef.get());
    }
}

(1)法の実演 - JVMのパラメータを変更しません。

業績は次のとおりです。

创建的弱引用为: java.lang.ref.WeakReference@6f94fa3e
Before GC: Weak Get = I am MyObject
After GC: Weak Get = null
删除的弱引用 obj 为: java.lang.ref.WeakReference@6f94fa3e
但是获取弱引用的对象 obj.get() 为: null
MyObject's finalize called

あなたは見ることができます:

GC前に、弱参照オブジェクトはガベージコレクタことが見出されておらず、従ってによりweakRef.get()対応するオブジェクトへの参照を取得することができます。

しかし限り、ガベージコレクションなど、弱参照が発見され、その後しようとまではすぐ。登録、参照キューを回復して、コメントを追加したweakRef.get()オブジェクト参照を取得するために失敗します。

(2)弱基準使用シナリオ:

弱参照は、シナリオの使用を参照してくださいjava.util.WeakHashMap

ソフト参照は、弱参照は、これらの不要。不足システムメモリのキャッシュされたデータを保持するのに非常に適している、キャッシュデータが復元されますが、それはメモリリークが発生することはありません。十分なメモリリソースは、順番にキャッシュできるデータそれによって使用されるシステムの応答速度を向上させる、長い時間のための本。

4ダングリング基準(ファントム参照)

また、ゴーストや幻影として知られている仮想基準は、引用文献には、ファントム参照の最も弱い一種であるオブジェクトの参照関係に保持し、参照は、ほぼ同じではない - 任意の時点でごみを収集する可能性があります。

仮想基準に合格しようとするとget()、強力な参照方法を取得するときは常に失敗します。

そして、それは架空の参照キューに関連して使用する必要があり、その役割は、ガベージコレクションプロセスを追跡することです。

参考文献仮想get()メソッドは、常に次のように実装され、nullを返します:

public T get() {
    return null;
}

私たちは、最初の2つのコードケース1を変更してみましょう:

package com.healchow.java.detail;

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.concurrent.TimeUnit;

public class PhantomRefTest {
    private static ReferenceQueue<MyObject> phantomQueue = new ReferenceQueue<>();

    private static class MyObject {
        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            System.out.println("MyObject's finalize called");
        }
        @Override
        public String toString() {
            return "I am MyObject";
        }
    }

    private static class CheckRefQueue implements Runnable {
        Reference<MyObject> obj = null;
        @Override
        public void run() {
            try {
                obj = (Reference<MyObject>) phantomQueue.remove();
                System.out.println("删除的虚引用 obj 为: " + obj);
                System.out.println("但是获取虚引用的对象 obj.get() 为: " + obj.get());
                System.exit(0);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyObject object = new MyObject();
        Reference<MyObject> phantomRef = new PhantomReference<>(object, phantomQueue);
        System.out.println("创建的虚引用为:" + phantomRef);
        new Thread(new CheckRefQueue()).start();

        object = null;
        TimeUnit.SECONDS.sleep(1);
        int i = 1;
        while (true) {
            System.out.println("第" + i++ + "次gc");
            System.gc();
            TimeUnit.SECONDS.sleep(1);
        }
    }
}

(1)法の実演 - JVMのパラメータを変更しません。

業績は次のとおりです。

创建的虚引用为:java.lang.ref.PhantomReference@6f94fa3e
第1次gc
MyObject's finalize called
第2次gc
删除的虚引用 obj 为: java.lang.ref.PhantomReference@6f94fa3e
但是获取虚引用的对象 obj.get() 为: null

あなたは見ることができます:

GC後、システムはゴミオブジェクトを検索し、メモリを再利用するためにファイナライズ()メソッドを呼び出しますが、すぐにファントム参照オブジェクトは、キューを回復参加しませんでした。

オブジェクトが実際にこの時点でクリアされる第二の時間GC、GCは、仮想キューを参照仮想基準オブジェクトに追加されます。

(2)仮想使用シナリオを参照しています。

ファントム参照の最大の効果は、オブジェクトの回復、クリーンアップリソースが破壊されているオブジェクトを追跡することです。

オブジェクトが正常に使用されていない場合は、オブジェクトのクラスは、オーバーロードfinalize()メソッドは、リソースオブジェクトを再利用することができますが誤っている場合、オブジェクトはこの例を上書きするように復活。finalize()方法:

public class Test {
    private static Test obj;
    
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        obj = this;
    }
}

テスト・オブジェクトの作成:obj = new Test();、そのようにobj = null;、呼び出した後にSystem.gc()オブジェクトを破壊しようとする試みを。

しかし、私はあなたが呼び出す回数に関係なく、ごめんないSystem.gc()再びしない限り、無駄にobj = null;オブジェクトを再利用します。

理由:それぞれのJVMが最もオーバーライドすることで、一度だけオブジェクトfinalize()メソッド、サンプルコード、super.finalize()後はそれが復活OBJようobjに割り当てられていたが、それは、ファイナライズ()メソッドは第二と呼ばれることはありません書き換えます回。

(3)仮想基準を通してオブジェクトをクリーンアップします

小さな断片の上記の説明は、書き換えfinalize()、以下のような方法は非常に信頼性がない、我々はオブジェクトコードで占められたリソースをクリーンアップするために仮想基準を使用することができます変更されます。

package com.healchow.java.detail;

import java.lang.ref.PhantomReference;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class PhantomRefTest2 {
    private static ReferenceQueue<MyObject> phantomQueue = new ReferenceQueue<>();
    private static Map<Reference<MyObject>, String> resourceMap = new HashMap<>();

    private static class MyObject {
        @Override
        protected void finalize() throws Throwable {
            super.finalize();
            System.out.println("MyObject's finalize called");
        }
        @Override
        public String toString() {
            return "I am MyObject";
        }
    }

    private static class CheckRefQueue implements Runnable {
        Reference<MyObject> refObj = null;

        @Override
        public void run() {
            try {
                refObj = (Reference<MyObject>) phantomQueue.remove();
                // 从资源Map中移除弱引用对象, 即手动释放资源
                Object value = resourceMap.get(refObj);
                System.out.println("clean resource: " + value);
                resourceMap.remove(refObj);

                System.out.println("删除的虚引用为: " + refObj);
                System.out.println("获取虚引用的对象 obj.get() 为: " + refObj.get());
                System.exit(0);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        MyObject object = new MyObject();
        Reference<MyObject> phantomRef = new PhantomReference<>(object, phantomQueue);
        System.out.println("创建的虚引用为: " + phantomRef);
        new Thread(new CheckRefQueue()).start();
        // 将创建的虚引用对象存入资源Map
        resourceMap.put(phantomRef, "Some Resources");

        object = null;
        TimeUnit.SECONDS.sleep(1);
        int i = 1;
        while (true) {
            System.out.println("第" + i++ + "次gc");
            System.gc();
            TimeUnit.SECONDS.sleep(1);
        }
    }
}

結果:

创建的虚引用为: java.lang.ref.PhantomReference@6f94fa3e
第1次gc
MyObject's finalize called
第2次gc
clean resource: Some Resources
删除的虚引用 obj 为: java.lang.ref.PhantomReference@6f94fa3e
但是获取虚引用的对象 obj.get() 为: null


参考資料

「Javaのパフォーマンスチューニング - 、Javaプログラムより速く、より安定しましょう」編、Geを鳴。

「Javaのヒープメモリhttp://blog.csdn.net/u013256816/article/details/50764532

著作権

侵害、ブロガー、確かにすぐに削除を連絡してください場合は、この記事では、元の作者に属します。

転載するには、記事ページの見かけ上の位置にある元のリンク、または他の自分の責任を明記してください。

おすすめ

転載: www.cnblogs.com/shoufeng/p/11491392.html