軟引用是用來(lái)描述一些還有用,但非必需的對(duì)象旁赊。只被軟引用關(guān)聯(lián)著的對(duì)象,在系統(tǒng)將要發(fā)生內(nèi)存溢出異常前,會(huì)把這些對(duì)象列進(jìn)回收范圍之中進(jìn)行第二次回收
,如果這次回收還沒(méi)有足夠的內(nèi)存,才會(huì)拋出內(nèi)存溢出異常晶乔。
軟引用通常用來(lái)實(shí)現(xiàn)內(nèi)存敏感的緩存桩警。比如: 高速緩存
就有用到軟引用驼卖。如果還有空閑內(nèi)存,就可以暫時(shí)保留緩存,當(dāng)內(nèi)存不足時(shí)清理掉,這樣就保證了使用緩存的同時(shí),不會(huì)耗盡內(nèi)存。
垃圾回收器在某個(gè)時(shí)刻決定回收軟可達(dá)的對(duì)象的時(shí)候,會(huì)清理軟引用,并可選地把引用存放到一個(gè)引用隊(duì)列(Reference Queue)。
類似弱引用,只不過(guò)Java虛擬機(jī)盡量讓軟引用的存活時(shí)間長(zhǎng)一些,迫不得已才清理。
啟動(dòng)下面的代碼時(shí)候需加入如下參數(shù):
-Xms10m -Xmx10m -XX:+PrintGCDetails
/**
* 軟引用的測(cè)試:內(nèi)存不足即回收
*/
public class SoftReferenceTest {
public static class User {
public User(int id, String name) {
this.id = id;
this.name = name;
}
public int id;
public String name;
@Override
public String toString() {
return "[id=" + id + ", name=" + name + "] ";
}
}
public static void main(String[] args) {
//創(chuàng)建對(duì)象,建立軟引用
// SoftReference<User> userSoftRef = new SoftReference<User>(new User(1, "songhk"));
//上面的一行代碼罗标,等價(jià)于如下的三行代碼
User u1 = new User(1, "young");
SoftReference<User> userSoftRef = new SoftReference<User>(u1);
u1 = null;//取消強(qiáng)引用
//從軟引用中重新獲得強(qiáng)引用對(duì)象
System.out.println(userSoftRef.get());
System.gc();
System.out.println("After GC:");
// //垃圾回收之后獲得軟引用中的對(duì)象
System.out.println(userSoftRef.get());//由于堆空間內(nèi)存足夠,所以不會(huì)回收軟引用的可達(dá)對(duì)象积蜻。
//
try {
//讓系統(tǒng)認(rèn)為內(nèi)存資源緊張闯割、不夠
byte[] b = new byte[1024 * 1024 * 7];
// byte[] b = new byte[1024 * 7168 - 635 * 1024];
} catch (Throwable e) {
e.printStackTrace();
} finally {
//再次從軟引用中獲取數(shù)據(jù)
System.out.println(userSoftRef.get());//在報(bào)OOM之前,垃圾回收器會(huì)回收軟引用的可達(dá)對(duì)象竿拆。
}
}
}