ソフトリファレンス、弱リファレンス、虚リファレンス-彼らの特徴と応用シーン

8639 ワード

  • なぜこの4つの引用があるのか
  • Javaの参照の定義は伝統的です.referenceのタイプのデータに格納されている数値が別のメモリの開始アドレスを表す場合、このメモリは参照を表すと呼ばれます.この定義は純粋ですが、狭すぎて、1つのオブジェクトがこの定義の下で引用されているか、引用されていないかの2つの状態しかなく、「食べ物の味がなく、捨てるのが惜しい」オブジェクトをどのように記述するかには力がありません.メモリ領域が十分である場合、メモリに保持できるオブジェクトについて説明したい.メモリ領域がゴミ収集後も非常に緊張している場合は、これらのオブジェクトを捨てることができます.多くのシステムのキャッシュ機能は、このようなアプリケーションシーンに合致しています.
    従来の2つのアプリケーションでは、オブジェクトのライフサイクルにおける複数の状態、オブジェクトがどのような状態を持っているかを記述することはできません.Javaにおいて、オブジェクトのライフサイクルは、以下の段階を含む.
  • 作成フェーズ(Created)
  • アプリケーションフェーズ(In Use)
  • 非可視フェーズ(Invisible)
  • 非到達段階(Unreachable)
  • 収集フェーズ(Collected)
  • 終了フェーズ(Finalized)
  • オブジェクト空間再割り当てフェーズ(De-allocated)
  • 作成フェーズ(Created)作成フェーズシステムでは、次の手順でオブジェクトの作成プロセスを完了します.
             
          
           static       
                ,           
                ,        
           ,           ,                
    

    アプリケーションフェーズ(In Use)オブジェクトは、少なくとも1つの強い参照によって保持される.
    非可視フェーズ(Invisible)オブジェクトが非可視フェーズにある場合、プログラム自体はオブジェクトの強い参照を持たないことを示します.これらの参照は依然として存在しますが.簡単に言えば、プログラムの実行はオブジェクトの役割ドメインを超えています.
    到達不可能フェーズ(Unreachable)オブジェクトが到達不可能フェーズにあるとは、オブジェクトが強い参照によって保持されなくなることを意味する.「非可視フェーズ」と比較して、「非可視フェーズ」とは、プログラムがオブジェクトの強い参照を持たないことを意味し、この場合、オブジェクトはJVMなどのシステムのいくつかのマウントされた静的変数またはスレッド、またはJNIなどの強い参照によって保持される可能性があり、これらの特別な強い参照は「GC root」と呼ばれる.これらのGC rootが存在すると、オブジェクトのメモリが漏洩し、回収できません.
    収集フェーズ(Collected)ゴミ回収器が、オブジェクトが「到達不可能フェーズ」にあることを発見し、ゴミ回収器がオブジェクトのメモリ領域の再割り当ての準備ができていることを発見すると、オブジェクトは「収集フェーズ」に入る.オブジェクトがfinalize()メソッドを書き換えた場合、そのメソッドの端末操作が実行される.ここでは特にfinazlie()をリロードしない方法を説明します!理由は2つあります.
    JVMのオブジェクトの割り当てと回収速度に影響します.このオブジェクトを割り当てる場合、JVMはゴミ回収器にそのオブジェクトを登録し、回収時にこのリロード方法を実行できるようにする必要があります.この方法の実行にはCPU時間がかかり、この方法を実行した後に回収操作が再実行される.すなわち、少なくともゴミ回収器がオブジェクトに対してGCを2回実行する必要がある.
    オブジェクトの再「復活」をもたらす可能性がありますfinalize()メソッドでは、他の強い参照が再びオブジェクトを保持している場合、オブジェクトのステータスが「収集フェーズ」から「適用フェーズ」に変更されます.これはJavaオブジェクトのライフサイクルプロセスを破壊し、「復活」したオブジェクトは後続のコード管理を利用しません.
    終了フェーズオブジェクトがfinalize()メソッドを実行した後も到達できない状態の場合、オブジェクトは終了フェーズに入ります.この段階では、ゴミ回収器がオブジェクト空間を回収するのを待つ.
    オブジェクト空間再分配フェーズゴミ回収器は、そのオブジェクトが占有するメモリ空間を回収または再分配すると、そのオブジェクトが完全に消失し、「オブジェクト空間再分配フェーズ」と呼ばれる.
  • どの4種類、それぞれどんな特徴があります
  • 強引用
  • 強いリファレンスは最も一般的なリファレンスを使用します.オブジェクトに強い参照がある場合、ゴミ収集器は決して回収しません.メモリ容量が不足すると、Java仮想マシンはOutOfM moryErrorのエラーを投げ出してプログラムを異常に終了させ、強い参照オブジェクトを勝手に回収してメモリ不足の問題を解決することはありません.
  • ソフトリファレンス
  • ソフトリファレンスは、まだ役に立つが必要ではないオブジェクトを記述するために使用されます.ソフトリファレンスに関連付けられたオブジェクトについては、メモリオーバーフロー異常が発生する前に、これらのオブジェクトを回収範囲に列挙して2回目の回収を行います.今回の回収で十分なメモリがない場合、メモリオーバーフロー異常が放出されます.
    /**
     *         
     *      -Xmx200m -XX:+PrintGC
     * Created by ccr at 2018/7/14.
     */
    public class SoftReferenceDemo {
    
        public static void main(String[] args) throws InterruptedException {
            //100M     
            byte[] cacheData = new byte[100 * 1024 * 1024];
            //           
            SoftReference cacheRef = new SoftReference<>(cacheData);
            //           
            cacheData = null;
            System.out.println("   GC " + cacheData);
            System.out.println("   GC " + cacheRef.get());
            //    GC          
            System.gc();
            //  GC
            Thread.sleep(500);
            System.out.println("   GC " + cacheData);
            System.out.println("   GC " + cacheRef.get());
    
            //     120M   ,           
            byte[] newData = new byte[120 * 1024 * 1024];
            System.out.println("   " + cacheData);
            System.out.println("   " + cacheRef.get());
        }
    
    }
    
       GC null
       GC [B@7d4991ad
    [GC (System.gc())  105728K->103248K(175104K), 0.0009623 secs]
    [Full GC (System.gc())  103248K->103139K(175104K), 0.0049909 secs]
       GC null
       GC [B@7d4991ad
    [GC (Allocation Failure)  103805K->103171K(175104K), 0.0027889 secs]
    [GC (Allocation Failure)  103171K->103171K(175104K), 0.0016018 secs]
    [Full GC (Allocation Failure)  103171K->103136K(175104K), 0.0089988 secs]
    [GC (Allocation Failure)  103136K->103136K(199680K), 0.0009408 secs]
    [Full GC (Allocation Failure)  103136K->719K(128512K), 0.0082685 secs]
       null
       null
    

    上記の例から分かるように、ソフトリファレンス関連オブジェクトはGCによって回収されない.JVMは空間を割り当てる際にHeapが不足すると対応するGCが行われるが、今回のGCではソフトリファレンス関連のオブジェクトは収集されないが、JVMでは1回の回収を行っても不足(Allocation Failure)であることが判明し、JVMでは2回目のGCを試みソフトリファレンス関連のオブジェクトを回収する.
    このようなメモリが十分であれば、GCは保持され、メモリが不足し、GCが収集される機能は、キャッシュの参照シーンに適しています.キャッシュを使用する場合、キャッシュにある場合はキャッシュから取得し、ない場合はデータベースから取得するという原則があります.キャッシュの存在は計算速度を速めるためです.キャッシュによってメモリ不足になり、プログラム全体がクラッシュすると、損をしません.
  • 弱引用
  • 弱いリファレンスは、ソフトリファレンスよりも強度が弱く、弱いリファレンスに関連付けられたオブジェクトを記述するためにも使用されます.ゴミ回収時に、このオブジェクトが弱いリファレンスにのみ関連付けられている場合(強いリファレンスに関連付けられていない場合)、このオブジェクトは回収されます.
    /**
     *             
     * Created by ccr at 2018/7/14.
     */
    public class WeakReferenceDemo {
        public static void main(String[] args) throws InterruptedException {
            //100M     
            byte[] cacheData = new byte[100 * 1024 * 1024];
            //           
            WeakReference cacheRef = new WeakReference<>(cacheData);
            System.out.println("   GC " + cacheData);
            System.out.println("   GC " + cacheRef.get());
            //    GC          
            System.gc();
            //  GC
            Thread.sleep(500);
            System.out.println("   GC " + cacheData);
            System.out.println("   GC " + cacheRef.get());
    
            //           
            cacheData = null;
            System.gc();
            //  GC
            Thread.sleep(500);
            System.out.println("   GC " + cacheData);
            System.out.println("   GC " + cacheRef.get());
        }
    }
       GC [B@7d4991ad
       GC [B@7d4991ad
       GC [B@7d4991ad
       GC [B@7d4991ad
       GC null
       GC null
    

    上記のコードから、弱い参照に関連付けられたオブジェクトが回収されるかどうかは、そのオブジェクトが他の強い参照を指しているかどうかにかかっていることがわかります.これは確かに理解しにくいが,弱い参照関連オブジェクトの生存周期と強い参照の差が少ない以上,直接強い参照を使ってよいのに,どうして弱い参照を作るのか.実は弱い引用は必然的に彼の応用シーンがある.
    static Map container = new HashMap<>();
    public static void putToContainer(Object key,Object value){
        container.put(key,value);
    }
    
    public static void main(String[] args) {
        //           
        Object key = new Object();
        Object value = new Object();
        putToContainer(key,value);
    
        //..........
        /**
         *               key         ,
         *                ,                  ?
         *   container             ,                    .
         *                      ,  ,    /            。
         *           。
         */
        key = null;
    }
    

    次のセクションは、Javaコア・テクノロジー・ボリューム1から抜粋します.WeakHashMapクラスを設計したのは、興味深い問題を解決するためです.値が1つあれば、対応するキーが使用されなくなり、どのような状況になりますか?あるキーに対する最後の参照が消滅し、この値を参照するオブジェクトがなくなったと仮定します.ただし、プログラム内の任意の部分にこのキーが表示されないため、このキー/値ペアはマッピングから削除できません.なぜゴミ回収機は削除できないのですか?不要なオブジェクトを削除するのはゴミ回収機の仕事ではないのでしょうか.
    残念なことに、事はこんなに簡単ではありません.ゴミ回収機はアクティブなオブジェクトを追跡します.マッピングオブジェクトがアクティブである限り、すべてのバケツもアクティブであり、回収できません.したがって,プログラムが長期にわたって生存しているマッピングテーブルから不要な値を削除する必要がある.あるいはWeakHashMapを使ってこのことを完成します.このデータ構造は、キーの一意の参照がハッシュ・エントリから来た場合、ゴミ回収器と連携してキー/値ペアを削除します.
    以下に、このメカニズムの内部動作を示します.WeakHashMap弱参照(weak references)を使用してキーを保存します.WeakReferenceオブジェクトは、参照を別のオブジェクトに保存します.ここでは、ハッシュキーです.このタイプのオブジェクトについては,ごみ回収器は特有の方法で処理される.通常、ゴミ回収器は、特定のオブジェクトが他の人に参照されていないことを発見した場合、それを回収します.ただし、オブジェクトがWeakReferenceでしか参照できない場合、ゴミ回収器はそれを回収しますが、このオブジェクトを参照する弱い参照をキューに入れます.WeakHashMapは、新しく追加された弱い参照を見つけるためにキューを周期的にチェックする.弱いリファレンスがキューに入ると、このキーは他の人に使用されず、収集されていることを意味します.すると、WeakHashMapは、対応するエントリを削除する.WeakHashMapが弱引用を用いたほか,ThreadLocalクラスでも弱引用を用いた.
  • 虚参照
  • 1つのオブジェクトに虚参照が存在するかどうかは、生存時間に影響を与えることはなく、虚引用によって1つのオブジェクトのインスタンスを取得することもできません.オブジェクトに虚参照関連付けを設定する唯一の目的は、このオブジェクトがコレクタによって回収されたときにシステム通知を受け取ることです.虚参照と弱参照は関連オブジェクトの回収に影響を及ぼさず、虚参照のみが生きている弱参照が関連オブジェクトを関連付けている場合、このオブジェクトは回収されます.これらの違いは、弱い参照のgetメソッドであり、虚参照のgetメソッドは常にnullを返し、弱い参照はReferenceQueueを使用することができ、虚参照はReferenceQueueと組み合わせて使用しなければならない.jdkの直接メモリの回収は虚参照に用いられる.jvmの自動メモリ管理の範囲はスタックメモリであるため、直接メモリはスタックメモリの外にあります(実はメモリマッピングファイルで、自分で仮想メモリ空間の関連概念を理解する)ため、直接メモリの割り当てと回収はUnsafe種類が操作され、javaは直接メモリを申請した後、スタックメモリに1つのオブジェクトを割り当ててこのスタックの外に保存された参照を保存し、このオブジェクトはゴミ収集器に管理され、このオブジェクトが回収されると、対応するのユーザースレッドに通知が表示され、直接メモリがクリーンアップされます.