Javaリファレンスタイプ
9215 ワード
JDK 1.2以降、javaは引用の概念を拡張し、引用を強引用、ソフト引用、弱引用、虚引用に分けた.強引用:コードの中に普遍的に存在する を永遠に回収しない.ソフトリファレンス:いくつかはまだ役に立つが、重要なオブジェクトではない.ソフトリファレンスに関連付けられたオブジェクトについては、システムがメモリオーバーフローを起こす前に、これらのオブジェクトを回収範囲に入れて2回目の回収を行う.今回の回収に十分なメモリがなければ、メモリオーバーフロー異常を投げ出すことはできない. 弱飲用:ゴミ収集器が作動すると、メモリが十分であるかどうかにかかわらず、飲用に関連する対象 のみが回収される.虚引用:1つのオブジェクトが虚引用の存在であるかどうかは、その生成時間に全く影響を及ぼさず、虚引用によって1つのオブジェクトインスタンスを取得することもできない.1つのオブジェクトに虚引用関連を設定する唯一の目的は、コレクタによって回収されたときに1つのシステム通知を受信することである.
強参照
JVMはGC時に強い参照のヒープインスタンスを解放しないので、ヒープ内GC後も十分なスペースが得られないとOOMが発生する
以上の例では、スタックに割り当てる
配列と集合に保存する参照もMapに保存する参照も強い参照である.
ソフトリファレンス
JVMはGC時にソフトリファレンスで参照されたオブジェクトインスタンスを解放するとは限らないが、いつ解放されるのだろうか.JVMがヒープメモリ不足を発見した場合のみ、GC時にソフトリファレンスのヒープメモリを解放します.
仮想マシンパラメータ
弱い参照
弱引用はソフトドリンクよりも弱い引用であり、JVMはGC時に弱引用を発見すれば、その引用したインスタンスを回収する
仮想マシンパラメータ
同じように実行して結果を見てみましょう
確かにGCごとに回収されています
リストに保存すると
結果は
配列に格納されていても同様に回収されます
ダミーリファレンス
虚引用はすべての引用タイプの中で最も弱いもので、虚引用で持たれているオブジェクトは持たれていない効果と基本的に同じです.虚引用からgetすると、空が得られます.それなら、なぜこのような引用を設計するのでしょうか.虚参照は参照キューと一緒にいなければならないため、いくつかのリソースのものを虚参照に配置して実行し、記録することができます.
仮想マシンパラメータ
Object obj = new Object()
のような引用を指し、強引用がまだ存在する限り、ゴミ収集器は参照されたオブジェクト強参照
JVMはGC時に強い参照のヒープインスタンスを解放しないので、ヒープ内GC後も十分なスペースが得られないとOOMが発生する
String str = new String("Hi");
以上の例では、スタックに割り当てる
str
がスタックに割り当てるStringの例を指しているが、str
の参照はこの例の強い参照である.配列と集合に保存する参照もMapに保存する参照も強い参照である.
ソフトリファレンス
JVMはGC時にソフトリファレンスで参照されたオブジェクトインスタンスを解放するとは限らないが、いつ解放されるのだろうか.JVMがヒープメモリ不足を発見した場合のみ、GC時にソフトリファレンスのヒープメモリを解放します.
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
public class TestSoft {
public static void main(String[] args) throws InterruptedException {
ReferenceQueue referenceQueue = new ReferenceQueue<>();
User user = new User();
SoftReference softReference = new SoftReference<>(user, referenceQueue);
user = null;
Thread t = new Thread(() -> {
while (true) {
Reference extends User> ref = referenceQueue.poll();
if (ref != null) {
System.out.println("Changed : " + ref);
break;
}
}
});
t.setDaemon(true);
t.start();
System.out.println("Before GC : " + " " + softReference.get());
System.gc();
System.out.println("After GC : " + softReference.get());
byte[] array = new byte[1024 * 920 * 7];
System.out.println("Alocate : " + softReference.get());
}
}
class User {
public String name;
}
仮想マシンパラメータ
-Xmx10M -Xms10M -XX:PrintGC
を指定し、このプログラムを実行した結果、次のようになります.[GC (Allocation Failure) 2048K->836K(9728K), 0.0023890 secs]
Before GC : testRef.User@404b9385
[GC (System.gc()) 1145K->844K(9728K), 0.0013400 secs]
[Full GC (System.gc()) 844K->750K(9728K), 0.0085260 secs]
After GC : testRef.User@404b9385
[GC (Allocation Failure) 788K->782K(9728K), 0.0003760 secs]
[GC (Allocation Failure) 782K->782K(9728K), 0.0002590 secs]
[Full GC (Allocation Failure) 782K->750K(9728K), 0.0043290 secs]
[GC (Allocation Failure) 750K->750K(9728K), 0.0004580 secs]
[Full GC (Allocation Failure) 750K->692K(9728K), 0.0079430 secs]
Changed : java.lang.ref.SoftReference@19366529
Alocate : null
SoftReference
インスタンスオブジェクトを構築する際、テストオブジェクトの追加に加えてReferenceQueue
インスタンスオブジェクトを追加し、オブジェクトの到達可能な状態が変化するとSoftReference
がReferenceQueue
キューに移動する.最後のPollという出力から、このオブジェクトは見えなくなった.弱い参照
弱引用はソフトドリンクよりも弱い引用であり、JVMはGC時に弱引用を発見すれば、その引用したインスタンスを回収する
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
public class TestSoft {
public static void main(String[] args) throws InterruptedException {
ReferenceQueue referenceQueue = new ReferenceQueue<>();
User user = new User();
WeakReference softReference = new WeakReference<>(user, referenceQueue);
//
user = null;
Thread t = new Thread(() -> {
while (true) {
Reference extends User> ref = referenceQueue.poll();
if (ref != null) {
System.out.println("Changed : " + ref);
break;
}
}
});
t.setDaemon(true);
t.start();
System.out.println("Before GC : " + " " + softReference.get());
System.gc();
System.out.println("After GC : " + softReference.get());
byte[] array = new byte[1024 * 920 * 7];
System.out.println("Alocate : " + softReference.get());
}
}
class User {}
仮想マシンパラメータ
-Xmx10M -Xms10M -XX:+PrintGC
を指定し、このプログラムを実行した結果、次のようになります.[GC (Allocation Failure) 2048K->800K(9728K), 0.0031060 secs]
Before GC : null
Changed : java.lang.ref.WeakReference@175fdc70[GC (System.gc()) 1084K->824K(9728K), 0.0011480 secs]
[Full GC (System.gc()) 824K->748K(9728K), 0.0088060 secs]
After GC : null
[GC (Allocation Failure) 807K->812K(9728K), 0.0010100 secs]
[GC (Allocation Failure) 812K->844K(9728K), 0.0004150 secs]
[Full GC (Allocation Failure) 844K->748K(9728K), 0.0090930 secs]
[GC (Allocation Failure) 748K->748K(9728K), 0.0003230 secs]
[Full GC (Allocation Failure) 748K->690K(9728K), 0.0082600 secs]
Alocate : null
WeakReference
がオブジェクトインスタンスに保存されている場合はどうなりますか?import java.lang.ref.WeakReference;
public class TestSoft {
public static void main(String[] args) throws InterruptedException {
WeakReferenceCache weakReferenceCache = new WeakReferenceCache();
weakReferenceCache.cache = new WeakReference<>(new User());
System.out.println("Before GC : " + weakReferenceCache.cache.get());
System.gc();
System.out.println("After GC : " + weakReferenceCache.cache.get());
byte[] array = new byte[1024 * 920 * 7];
System.out.println("Alocate GC : " + weakReferenceCache.cache.get());
}
}
class WeakReferenceCache {
public WeakReference cache;
}
class User {
}
同じように実行して結果を見てみましょう
Before GC : User@41629346
After GC : null
Alocate GC : null
確かにGCごとに回収されています
リストに保存すると
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
public class TestSoft {
public static void main(String[] args) throws InterruptedException {
WeakReferenceCache weakReferenceCache = new WeakReferenceCache();
for (int i = 0; i < 10; i++) {
WeakReference softReference = new WeakReference<>(new User());
weakReferenceCache.cache.add(softReference);
}
System.out.println("Before GC : ");
weakReferenceCache.cache.forEach(cache -> {
System.out.println(cache.get());
});
System.gc();
System.out.println("After GC : ");
weakReferenceCache.cache.forEach(cache -> {
System.out.println(cache.get());
});
byte[] array = new byte[1024 * 920 * 7];
System.out.println("Alocate GC : ");
weakReferenceCache.cache.forEach(cache -> {
System.out.println(cache.get());
});
}
}
class WeakReferenceCache {
public List> cache = new ArrayList<>();
}
class User {
}
結果は
Before GC :
User@6433a2
User@5910e440
User@6267c3bb
User@533ddba
User@246b179d
User@7a07c5b4
User@26a1ab54
User@3d646c37
User@41cf53f9
User@5a10411
After GC :
null
null
null
null
null
null
null
null
null
null
Alocate GC :
null
null
null
null
null
null
null
null
null
null
配列に格納されていても同様に回収されます
ダミーリファレンス
虚引用はすべての引用タイプの中で最も弱いもので、虚引用で持たれているオブジェクトは持たれていない効果と基本的に同じです.虚引用からgetすると、空が得られます.それなら、なぜこのような引用を設計するのでしょうか.虚参照は参照キューと一緒にいなければならないため、いくつかのリソースのものを虚参照に配置して実行し、記録することができます.
import java.lang.ref.*;
public class TestSoft {
public static void main(String[] args) throws InterruptedException {
ReferenceQueue referenceQueue = new ReferenceQueue<>();
User user = new User();
PhantomReference softReference = new PhantomReference<>(user, referenceQueue);
user = null;
Thread t = new Thread(() -> {
while (true) {
Reference extends User> ref = referenceQueue.poll();
if (ref != null) {
System.out.println("Changed : " + System.currentTimeMillis());
break;
}
}
});
t.setDaemon(true);
t.start();
System.out.println("Before GC : " + System.currentTimeMillis() + " " + softReference.get());
System.gc();
System.out.println("After GC : " + softReference.get());
byte[] array = new byte[1024 * 920 * 7];
System.out.println("Alocate : " + softReference.get());
}
}
class User {}
仮想マシンパラメータ
-Xmx30M -Xms30M -XX:+PrintGC
を指定し、このプログラムを実行した結果、次のようになります.Before GC : 1462461362835 null
[GC (System.gc()) 2806K->904K(29696K), 0.0033390 secs]
[Full GC (System.gc()) 904K->779K(29696K), 0.0095950 secs]
Changed : 1462461362850
After GC : null
Alocate : null