Java/Androidには4つの参照タイプがあります。
強力な参照 - 強力な参照
ソフトリファレンス - ソフトリファレンス
弱い参照 - 弱い参照
Phantom Reference-仮想引用
異なる参照タイプには異なる特性があり、さまざまな使用シナリオにも対応しています。
1.強力な参照 - 強いリファレンス
実際のエンコーディングで最も一般的なタイプの参照。次のような一般的な形式:a a = new a();など。強い基準自体はスタックメモリに保存され、アドレスをメモリ内のオブジェクトに保存します。一般的に、メモリ内のオブジェクトへの強い参照がなくなった場合、Garbage Collection Machineは、このメモリ上で行われる可能性のあるごみ収集を検討し始めます。エンコードの場合:a = null、この時点で、ヒープに割り当てられて作成されたアドレスには、他の参照はありません。システムがガベージコレクションを実行すると、ヒープメモリはゴミ収集されます。
ソフトレファレンス、弱者、およびファントミレファレンスはすべて、クラスjava.lang.ref.Referenceのサブクラスです。参照は、抽象的なベースクラスとして、サブクラスオブジェクトの基本操作を定義します。参照サブクラスにはすべて、次の特性があります。
1.参照サブクラスは、パラメーター化なしに直接作成することはできません。少なくとも強力な参照オブジェクトを構成パラメーターとして使用して、それぞれのサブクラスオブジェクトを作成する必要があります。
2。オブジェクトは、構造パラメーターとして強い基準オブジェクトを使用して1に作成されるため、元々の強い参照によって指摘されたヒープメモリ内のオブジェクトは、強力な参照自体に直接関係しなくなりますが、参照のサブクラスオブジェクトの参照と特定の接続もあります。そして、この接続は、オブジェクトのごみ収集に影響を与える可能性があります。
インジケーターオブジェクトのごみ収集(ヒープメモリ内のオブジェクトへの強い参照)に対するさまざまなサブクラスオブジェクトのさまざまな影響特性によれば、3つのサブクラスが形成されます。
2.ソフトリファレンス - ソフトリファレンス
ソフトリファレンスの一般的な使用形式は次のとおりです。
a a = new a();
softreference <a> sra = new softreference <a>(a);
パラメーターとしてのオブジェクトの強力な参照を介して、SoftReferenceオブジェクトが作成され、スタックメモリ内のWRAがこのオブジェクトを指します。
この時点で、次のエンコードが実行されます:a = null。オブジェクトAが元々指し示していたゴミコレクションにどのような影響がありますか?
次のプログラムの出力結果を見てみましょう。
import java.lang.ref.softreference; public class referenceTEST {public static void main(string [] args){a a = new a(); softreference <a> sra = new softreference <a>(a); a = null; if(sra.get()== null){system.out.println( "オブジェクトがガベージ収集プロセスに入る"); } else {system.out.println( "オブジェクトはまだリサイクルされていません" + sra.get()); } // Garbage Collection System.gc(); if(sra.get()== null){system.out.println( "オブジェクトがガベージコレクションプロセスを入力する"); } else {system.out.println( "オブジェクトはまだリサイクルされていません" + sra.get()); }}} class a {} ##出力の結果は次のとおりです。
1オブジェクトはリサイクルされていません@4807ccf62オブジェクトは@4807ccf6をリサイクルしていません
a = nullの場合、ヒープメモリ内のオブジェクトはもはや強い参照を持たなくなりますが、SRAがAオブジェクトを指すと参照するファッショナブルなオブジェクトがあります。 Garbage Collectorがまだガベージコレクションを実行していない可能性が高いため、Sra.get()メソッドが初めてこのインジケータオブジェクトを返すように呼ばれる場合、GET()はこの時点で結果を得ています。プログラムがsystem.gc()を実行するとき; sra.get()を介してガベージコレクションを強制すると、示されたオブジェクトがまだ取得できることがわかります。それでは、ソフト参照によって示されるオブジェクトはいつゴミ収集され始めますか?次の2つの条件を満たす必要があります。
1.それが示すオブジェクトには、それを指す強力な参照オブジェクトがない場合。
2。仮想マシンのメモリが不十分な場合。
したがって、ソフトレファレーションは、仮想マシンのメモリが不十分になるまで、オブジェクトがヒープメモリを占有することを示す時間を延長します。ゴミコレクターは、このヒープメモリスペースをリサイクルしません。
3.ウィーク参照 - 弱いリファレンス
同様に、ソフト参照の一般的な使用形式は次のとおりです。
a a = new a();
weakreference <a> wra = new weakReference <a>(a);
このオブジェクトを指す強い基準がない場合、そのガベージコレクションの特性は何ですか?
import java.lang.ref.weakreference; public class referenceTest {public static void main(string [] args){a a = new a(); weakreference <a> wra = new weakReference <a>(a); a = null; if(wra.get()== null){system.out.println( "オブジェクトがガベージコレクションプロセスに入る"); } else {system.out.println( "オブジェクトはまだリサイクルされていません" + wra.get()); } // Garbage Collection System.gc(); if(wra.get()== null){system.out.println( "オブジェクトがガベージコレクションプロセスに入る"); } else {system.out.println( "オブジェクトはまだリサイクルされていません" + wra.get()); }}} class a {} ##出力の結果は次のとおりです。
オブジェクトはまだリサイクルされていませんが、@52E5376AAオブジェクトがガベージコレクションプロセスに入ります
最初の結果出力は上記のように説明されています。ガベージコレクションの後、wra.get()はnullを返し、オブジェクトがガベージコレクションプロセスに入力したことを示します。したがって、弱い引用の特性は次のように要約されています。
WeakReferenceは、元の強い参照オブジェクトのガベージコレクションのタイミングを変更しません。オブジェクトに強い参照オブジェクトがないことを示すと、オブジェクトは通常のガベージ収集プロセスに入ります。
それで、この特徴に基づいて、質問があります:弱者の重要性は何ですか?
主な使用シナリオは次のとおりです。現在、強力な参照オブジェクトを指す強力な参照があります。現時点では、ビジネスニーズのため、このオブジェクトへの参照を増やす必要があり、同時に、このリファレンスのガベージコレクションのタイミングを変更することを意図したものではありません。現時点では、弱者はニーズを満たしているだけで、ライフサイクルのあるいくつかのシナリオによく見られます。
以下は、Androidでの弱者を使用するためのシナリオです - 静的な内部クラスと弱いために、アクティビティで考えられるハンドラーメモリリーク問題を解決するための弱者です。
アクティビティでは、データを取得してハンドラー-SendMessageメソッドを使用する新しいスレッドを作成する必要があります。このプロセスの一般的なコードは次のとおりです。
パブリッククラスのMainActivityはアクティビティを拡張します{// ... private intページ;プライベートハンドラーハンドラー= new Handler(){@Override public void handlemessage(message msg){if(msg.what == 1){// ... page ++; } それ以外 { //... } }; }; @Override Protected void oncreate(bundle savedinstancestate){super.oncreate(savedinstancestate); setContentView(r.layout.activity_main); // ... newスレッド(new runnable(){@override public void run(){// .. message msg = message.obtain(); msg.what = 1; //msg.obj = xx; handler.sendmessage(msg);}})。start(); start(); // ...}}リンクを実行するEclispeでは、警告メッセージが表示されます。このハンドラークラスは静的またはリークが発生する可能性があります...クリックしてこの情報を表示します。これは、詳細の問題を説明し、示唆的なソリューションを提供します。
問題:ハンドラーのクラスが外側のクラスへの参照を保持しないようにします:ハンドラーリークこのハンドラーは内側のクラスとして宣言されているため、外側のクラスがゴミ収集されないようにする可能性があります。ハンドラーがメインスレッド以外のスレッドにルーパーまたはメッセージqueueを使用している場合、問題はありません。ハンドラーがメインスレッドのルーパーまたはメッセージqueueを使用している場合、次のようにハンドラー宣言を修正する必要があります。ハンドラーを静的クラスとして宣言します。外側のクラスでは、外側のクラスに弱いreferenceをインスタンス化し、ハンドラーをインスタンス化するときにこのオブジェクトをハンドラーに渡します。 WeakReferenceオブジェクトを使用して、外側クラスのメンバーにすべての参照を作成します。
一般的な意味は、外部アクティビティオブジェクトを示すために、ハンドラーを内部静的クラスとして定義し、この静的な内部クラスの弱者への参照を定義することをお勧めします。
問題分析:
アクティビティには独自のライフサイクルがあります。アクティビティで新しく開かれたスレッドの実行プロセス中、ユーザーはバックキーを押すか、システムがメモリが不十分であるなど、このアクティビティをリサイクルすることができます。アクティビティ内の新たに発売されたスレッドは、アクティビティ自体のサイクルに従わないため、つまり、スレッドとハンドラーのハンドルメッジの存在によりアクティビティがOndestroyを実行するとき、システムは元々、このアクティビティのメモリ回復を実行することを望んでいます。
したがって、アクティビティでハンドラーを使用する場合、一方では、外部クラスから分離し、外部クラスへの参照を保持しないように、静的な内部クラス形式として定義する必要があります。同時に、ハンドラーのハンドラーは一般にアクティビティのプロパティにアクセスまたは変更する必要があるため、現時点では、このアクティビティを指す弱者は、アクティビティのメモリ回復に影響しないようにハンドラー内で定義する必要があります。同時に、通常の状況では、アクティビティの特性にアクセスできます。
Googleの公式推奨事項は次のとおりです。
パブリッククラスのMainActivityはアクティビティを拡張します{// ... private intページ;プライベートマイハンドラーmmyhandler = new myhandler(this);プライベート静的クラスMyHandler拡張ハンドラー{private weakReference <mainActivity> wractivity; Public MyHandler(MainActivity Activity){this.wractivity = new weakReference <mainActivity>(Activity); } @Override public void handlemessage(message msg){if(wractivity.get()== null){return; } mainActivity mactivity = wractivity.get(); if(msg.what == 1){// ... mactivity.page ++; } else {// ...}}} @Override Protected void oncreate(bundle savedinstancestate){super.oncreate(savedinstancestate); setContentView(r.layout.activity_main); // ... newスレッド(new runnable(){@override public void run(){// .. message msg = message.obtain(); msg.what = 1; //msg.obj = xx; mmyhandler.sendmessage(msg);}}}})。start(); start(); // ...}}SoftreferenceとWeakReferenceの場合、コンストラクターパラメーターリファレンスキュー<t>もあり、ソフトラファレーションまたは弱者で示されるオブジェクトが実際にガベージが収集されると、その参照はリファレンスキューに配置されます。上記のように、softreferenceまたはweakReferenceのget()方法がnullを返す場合、それが示すオブジェクトがガベージ収集プロセスに入ったことを示すだけであり、オブジェクトは現時点ではゴミが収集されなかった可能性があることに注意してください。ごみ収集されたことを確認した後にのみ、参照キューがある場合、その参照はリファレンスキューに配置されます。
以下の例を参照してください。
public class referencetEtest {public static void main(string [] args){a a = new a(); weakreference <a> wra = new weakReference <a>(a); a = null; if(wra.get()== null){system.out.println( "オブジェクトがガベージコレクションプロセスに入る"); } else {system.out.println( "オブジェクトはまだリサイクルされていません" + wra.get()); } // Garbage Collection System.gc(); if(wra.get()== null){system.out.println( "オブジェクトがガベージコレクションプロセスに入る"); } else {system.out.println( "オブジェクトはまだリサイクルされていません" + wra.get()); }}} class a {@Override Protected void finalize()throws throws {super.finalize(); system.out.println( "in a finalize"); }} ##出力の結果は次のとおりです。
1オブジェクトはリサイクルされていません@46993AAA2ファイナライズでオブジェクトがリサイクルされました3
これは、上記の「ごみ収集プロセスの入力」という声明も検証します。参照キューと組み合わせたコードを見てみましょう。
public class referencetEtest {public static void main(string [] args){a a = new a(); ReferenceQueue <a> rq = new ReferenceQueue <a>(); weakreference <a> wra = new weakReference <a>(a、rq); a = null; if(wra.get()== null){system.out.println( "オブジェクトがガベージコレクションプロセスに入る"); } else {system.out.println( "オブジェクトはまだリサイクルされていません" + wra.get()); } system.out.println( "rq item:" + rq.poll()); // Garbage Collection System.gc(); if(wra.get()== null){system.out.println( "オブジェクトがガベージコレクションプロセスに入る"); } else {system.out.println( "オブジェクトはまだリサイクルされていません" + wra.get()); } /* try {thread.sleep(1000); } catch(arturnedexception e){e.printstacktrace(); } */ system.out.println( "rq item:" + rq.poll()); }} class a {@Override Protected void finalize()throws throws {super.finalize(); system.out.println( "in a finalize"); }} ##出力の結果は次のとおりです。
オブジェクトはまだリサイクルされていません@302B2C81RQアイテム:nullaオブジェクトがガベージコレクションプロセスRQアイテムに入る:nullin aファイナライズ
したがって、「ガベージ収集プロセスのみに入力するソフトレファレンスまたは弱者参照がリファレンスキューに追加されていない」と確認されています。
public class referencetEtest {public static void main(string [] args){a a = new a(); ReferenceQueue <a> rq = new ReferenceQueue <a>(); weakreference <a> wra = new weakReference <a>(a、rq); a = null; if(wra.get()== null){system.out.println( "オブジェクトがガベージコレクションプロセスに入る"); } else {system.out.println( "オブジェクトはまだリサイクルされていません" + wra.get()); } system.out.println( "rq item:" + rq.poll()); // Garbage Collection System.gc(); if(wra.get()== null){system.out.println( "オブジェクトがガベージコレクションプロセスに入る"); } else {system.out.println( "オブジェクトはまだリサイクルされていません" + wra.get()); } try {thread.sleep(1); } catch(arturnedexception e){e.printstacktrace(); } system.out.println( "rq item:" + rq.poll()); }} class a {@Override Protected void finalize()throws throws {super.finalize(); system.out.println( "in a finalize"); }} ##出力の結果は次のとおりです。
オブジェクトはまだリサイクルされていません@6276e1dbrqアイテム:nullaオブジェクトは、finalizerqアイテムのガベージコレクションプロセスに入ります:java.lang.ref.weakreference@645064f
これにより、上記の声明が確認されます。
4.PhantomReference
SoftreferenceまたはWeakReferenceと比較して、幻想の主な違いは次の点に反映されています。
1。ファントマレファレンスには、コンストラクターファントレフェンスが1つしかない(T Reference、ReferenceQueue <?super t> q)ため、PhantomreferenceはReferenceQueueと組み合わせて使用する必要があります。
2。幻想を指すインジケータオブジェクトに強い参照があるかどうかに関係なく、幻想のget()メソッドは結果nullを返します。
public class referencetEtest {public static void main(string [] args){a a = new a(); ReferenceQueue <a> rq = new ReferenceQueue <a>(); Phantomreference <a> pra = new phantomreference <a>(a、rq); System.out.println( "pra.get():" + pra.get()); a = null; System.gc(); {thread.sleep(1); } catch(arturnedexception e){e.printstacktrace(); } system.out.println( "rq item:" + rq.poll()); }} class a {} ##出力の結果は次のとおりです。
pra.get():nullrqアイテム:java.lang.ref.phantomreference@1da12fc0
Thread.Sleep(1);コードでは、上記の例と同じ機能を機能させ、どちらもガベージコレクションスレッドが実行できることを確認します。それ以外の場合、実際にゴミ収集されずにガベージ収集プロセスに入るインジケータオブジェクトへの仮想参照は、幻想に追加されません。
WeakReferenceと同様に、ファントマレファレンスは、その指示オブジェクトのごみ収集タイミングを変更しません。リファレンスキューの関数は、オブジェクトがガベージが収集されたかどうかを示すソフトレファレンス/弱者/幻想を聞くために主に使用されると結論付けることができます。
上記は、Java/Androidリファレンスタイプの包括的な分析と、編集者がお客様に提供した使用の完全な内容です。それがあなたに役立ち、wulin.comをもっとサポートすることを願っています〜