文章目錄
- 1.引言
- 2.強引用
- 3.軟引用
- 4.弱引用
- 5.虛引用
1.引言
其實強引用、軟引用、弱引用、虛引用這四個概念非常簡單好記。
在開頭先總結一下這四個引用的特點吧。
強引用:gc時不會回收
軟引用:隻有在記憶體不夠用時,gc才會回收
弱引用:隻要gc就會回收
虛引用:是否回收都找不到引用的對象,僅用于管理直接記憶體
接下來詳細看看這四種引用,結合代碼,深刻的體會一下。
2.強引用
即我們平時最常見的:
Object object = new Object();
隻要一個對象有強引用,垃圾回收器就不會進行回收。即便記憶體不夠了,抛出OutOfMemoryError異常也不會回收。
/**
* 一個對象
* 重寫finalize方法,可以知道已經被回收的狀态
*
* @author
* @date 2020-05-23
*/
public class OneObject {
@Override
protected void finalize() throws Throwable {
System.out.println("啊哦~OneObject被回收了");
}
}
/**
* 強引用例子
*
* @author
* @date 2020-05-23
*/
public class ShowStrongReference {
public static void main(String[] args) {
// 直接new一個對象,就是強引用
OneObject oneObject = new OneObject();
System.out.println("輸出對象位址:" + oneObject);
System.gc();
System.out.println("第一次gc後輸出對象位址:" + oneObject);
oneObject = null;
System.gc();
System.out.println("置為null後gc輸出對象位址:" + oneObject);
}
}
執行代碼,可以看到以下輸出:
輸出對象位址:com.esparks.pandora.learning.references.OneObject@72ea2f77
第一次gc後輸出對象位址:com.esparks.pandora.learning.references.OneObject@72ea2f77
置為null後gc輸出對象位址:null
啊哦~OneObject被回收了
3.軟引用
需要通過SoftReference對象實作:
SoftReference<OneObject> oneObjectSr = new SoftReference<>(new OneObject());
當記憶體足夠的時候,垃圾回收器不會進行回收。當記憶體不夠時,就會回收隻存在軟引用的對象釋放記憶體。
常用于本地緩存處理。
/**
* 軟引用
* 記憶體不夠了就會回收
* 注意,運作時需要保證heap大小為35m,即小于實驗中全部對象的大小,才能觸發gc
* -Xmx35m
*
* @author
* @date 2020-05-23
*/
public class ShowSoftReference {
public static void main(String[] args) {
// 我們需要通過SoftReference來建立軟引用
SoftReference<OneObject> oneObjectSr = new SoftReference<>(new OneObject());
// 我們這裡建立一個大小為20m的數組
SoftReference<byte[]> arraySr = new SoftReference<>(new byte[1024 * 1024 * 20]);
System.out.println("軟引用對象oneObjectSr的位址:" + oneObjectSr);
System.out.println("通過oneObjectSr關聯的oneObject對象的位址:" + oneObjectSr.get());
System.out.println("數組的位址:" + arraySr.get());
System.gc();
System.out.println("正常gc一次之後,oneObject對象并沒有回收。位址" + oneObjectSr.get());
// 再建立另一個大小為20m的數組,這樣heap就不夠大了,進而系統自動gc。如果依舊不夠,會把已有的軟引用關聯的對象都回收掉。
System.out.println("建立另一個大小為20m的數組otherArray");
byte[] otherArray = new byte[1024 * 1024 * 20];
System.out.println("otherArray的位址:" + otherArray);
// gc後,軟引用對象還在,但是通過軟引用對象建立的對象就被回收了
System.out.println("現在srObject的位址:" + arraySr);
System.out.println("現在srObject中oneObject對象的位址:" + arraySr.get());
System.out.println("剛才的數組對象也被回收啦,位址:" + arraySr.get());
}
}
執行代碼,可以看到以下輸出:
軟引用對象oneObjectSr的位址:java.lang.ref.SoftReference@72ea2f77
通過oneObjectSr關聯的oneObject對象的位址:com.esparks.pandora.learning.references.OneObject@33c7353a
數組的位址:[B@681a9515
正常gc一次之後,oneObject對象并沒有回收。位址com.esparks.pandora.learning.references.OneObject@33c7353a
建立另一個大小為20m的數組otherArray
啊哦~OneObject被回收了
otherArray的位址:[B@3af49f1c
現在srObject的位址:java.lang.ref.SoftReference@19469ea2
現在srObject中oneObject對象的位址:null
剛才的數組對象也被回收啦,位址:null
4.弱引用
需要通過WeakReference對象實作:
WeakReference<OneObject> oneObjectWr = new WeakReference<>(new OneObject());
隻要發生gc,就會回收隻存在弱引用的對象。
常用于Threadlocal。
/**
* 弱引用
* 隻要gc就會回收
*
* @author
* @date 2020-05-23
*/
public class ShowWeakReference {
public static void main(String[] args) {
// 我們需要通過WeakReference來建立弱引用
WeakReference<OneObject> objectWr = new WeakReference<>(new OneObject());
System.out.println("弱引用objectWr的位址:" + objectWr);
System.out.println("弱引用objectWr關聯的oneObject對象的位址:" + objectWr.get());
System.gc();
// gc後,弱引用對象還在,但是通過弱引用對象建立的對象就被回收了
System.out.println("gc後,弱引用objectWr的位址:" + objectWr);
System.out.println("gc後,弱引用objectWr關聯的oneObject對象的位址:" + objectWr.get());
}
}
5.虛引用
需要通過PhantomReference對象和ReferenceQueue實作:
private ReferenceQueue<OneObject> queue = new ReferenceQueue<>();
PhantomReference<OneObject> oneObjectPr = new PhantomReference<>(new OneObject(), queue);
無論是否gc,其實都擷取不到通過PhantomReference建立的對象。
其僅用于管理直接記憶體,起到通知的作用。
/**
* 虛引用
* 隻用于管理直接記憶體,起到通知的作用
*
* @author
* @date 2020-05-23
*/
public class ShowPhantomReference {
/**
* 虛引用需要的隊列
*/
private static final ReferenceQueue<OneObject> QUEUE = new ReferenceQueue<>();
public static void main(String[] args) {
// 我們需要通過WeakReference來建立虛引用
PhantomReference<OneObject> objectPr = new PhantomReference<>(new OneObject(), QUEUE);
System.out.println("虛引用objectPr的位址:" + objectPr);
System.out.println("虛引用objectPr關聯的oneObject對象的位址:" + objectPr.get());
// 觸發gc,然後檢查隊列中是否有虛引用
while (true) {
System.gc();
Reference<? extends OneObject> poll = QUEUE.poll();
if (poll != null) {
System.out.println("隊列裡找到objectPr啦" + poll);
break;
}
}
}
}
虛引用objectPr的位址:java.lang.ref.PhantomReference@72ea2f77
虛引用objectPr關聯的oneObject對象的位址:null
啊哦~OneObject被回收了
隊列裡找到objectPr啦java.lang.ref.PhantomReference@72ea2f77