强引用
最常见的引用赋值Object object = new Object();
,无论任何情况下,即使OOM,只有强引用关系还在,垃圾收集器就永远不会回收被该类对象。
public static void StronglyReference() {
byte[] object = new byte[ 1024 * 500 ];
byte[] stranger = object;
object = null;
System.gc();// Full GC
try {
Thread.sleep(1000);//回收線程可能延遲
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(stranger);
}
[B@1b6d3586
软引用
在内存不足时(老年代内存不足,即即将发生OOM,需要进行Full GC),垃圾收集器会将被软引用关联的对象回收。如果回收后还没有足够的内存,才抛出内存溢出异常(注意,如果回收后有足够空间就不报OOM)。
VM参数-Xms12m -Xmx12m
,可知Eden是3.2M,老年代是8M
/**
* -Xms12m -Xmx12m
* 新生代 :老年代 = 1 : 2
* Eden : Survivor0 : Survivor1 = 8 : 1 : 1
* 所以Eden是3.2M,老年代是8M
*/
public static void SoftReferenceTest() {
byte[] object = new byte[ 1024 * 500 ];// 500K,放到新生代
SoftReference<Object> softReference = new SoftReference<>(object);
object = null;
System.gc();// 此時內存充足,軟引用不會被回收,Full GC放到老年代
try {
Thread.sleep(1000);//回收線程可能延遲
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("對象:" + softReference.get());
// 放一個大對象,超過老年代容量,老年代放不下,OOM
// try {
// byte[] newObject = new byte[ 1024 * 1024 * 8 ];// 8M
// } catch (Throwable e) {// OOM
// e.printStackTrace();
// }
// 這時新對象剛好在老年代放得下,軟引用放不下,恰好被回收
// byte[] newObject = new byte[ 1024 * 1024 * 7 ];
// 這時老年代放得下舊對象和新對象,軟引用不回收
byte[] newObject = new byte[ 1024 * 1024 * 6 ];
System.out.println("對象:" + softReference.get());
}
新旧对象均放不下
對象:[B@1b6d3586
java.lang.OutOfMemoryError: Java heap space
at com.jvm.Main.SoftReferenceTest(Main.java:44)
at com.jvm.Main.main(Main.java:98)
對象:null
只能放新对象
對象:[B@1b6d3586
對象:null
新旧对象均能放得下
對象:[B@1b6d3586
對象:[B@1b6d3586
弱引用
被弱引用关联的对象只能生存到下一次垃圾收集发生为止。下一次垃圾收集时,不管当前内存是否足够,都会回收只被弱引用关联的对象。
public static void WeakReferenceTest() {
byte[] object = new byte[ 1024 * 1024 ];// 1M,放到新生代
WeakReference<Object> weakReference = new WeakReference<>(object);
object = null;
System.out.println("對象:" + weakReference.get());
System.gc();// 弱引用GC就回收
try {
Thread.sleep(1000);//回收線程可能延遲
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("對象:" + weakReference.get());
}
對象:[B@1b6d3586
對象:null
虚引用
一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象的实例。为一个对象设置虚引用关联的唯一目的是为了能在这个对象被回收时收到一个系统通知。
public static void PhantomReferenceTest() {
Object object = new Object();//被回收的對象
ReferenceQueue<Object> queue = new ReferenceQueue<>();
//虛引用必須提供一個引用隊列,在對象被回收時通過引用隊列發送通知
PhantomReference<Object> phantomReference = new PhantomReference<>(object, queue);
System.out.println(phantomReference.get());// 無法通過虛引用獲取對象實例
object = null;//不引用該對象
System.gc();//回收
try {
Thread.sleep(1000);//回收線程可能延遲
} catch (InterruptedException e) {
e.printStackTrace();
}
//虛引用被回收,可以在引用隊列找到該對象的信息
PhantomReference<Object> phantom = (PhantomReference<Object>) queue.poll();
if (phantom != null) {
System.out.println("對象已回收:" + phantom);
} else {
System.out.println("對象未回收");
}
}
null
對象已回收:java.lang.ref.PhantomReference@1b6d3586