java內(nèi)存管理分為內(nèi)存分配和內(nèi)存回收今妄,都不需要程序員負(fù)責(zé)焰手,垃圾回收的機(jī)制主要是看對(duì)象是否有引用指向該對(duì)象
java對(duì)象的引用包括
強(qiáng)引用栅贴,軟引用,弱引用联予,虛引用
Java中提供這四種引用類型主要有兩個(gè)目的:
1. 是可以讓程序員通過(guò)代碼的方式?jīng)Q定某些對(duì)象的生命周期;
2. 是有利于JVM進(jìn)行垃圾回收材原。
一沸久、 強(qiáng)引用(StrongReference)
強(qiáng)引用是使用最普遍的引用。只要某個(gè)對(duì)象有強(qiáng)引用與之關(guān)聯(lián)余蟹,JVM必定不會(huì)回收這個(gè)對(duì)象卷胯,即使在內(nèi)存不足的情況下,JVM寧愿拋出OutOfMemory錯(cuò)誤也不會(huì)回收這種對(duì)象
如下:
Objectobject=newObject();
Stringstr="hello";
如果想中斷強(qiáng)引用和某個(gè)對(duì)象之間的關(guān)聯(lián)威酒,可以顯示地將引用賦值為null窑睁,這樣一來(lái)的話挺峡,JVM在合適的時(shí)間就會(huì)回收該對(duì)象,如下:
object=null;
str=null;
再看一下源碼中如何解決強(qiáng)引用轉(zhuǎn)為軟引用后的回收
/**
? ? * 這是ArrayList中的清空數(shù)組的方法
? ? */private transient Object[]elementData;
public void clear(){
modCount++;// clear to let GC do its work
for(inti=0;i<size;i++
elementData[i]=null;
size=0;
}
注:在ArrayList類中定義了一個(gè)私有的變量elementData數(shù)組担钮,在調(diào)用方法清空數(shù)組時(shí)可以看到為每個(gè)數(shù)組內(nèi)容賦值為null橱赠。不同于elementData=null,強(qiáng)引用仍然存在箫津,避免在后續(xù)調(diào)用 add()等方法添加元素時(shí)進(jìn)行重新的內(nèi)存分配病线。使用如clear()方法中釋放內(nèi)存的方法對(duì)數(shù)組中存放的引用類型特別適用,這樣就可以及時(shí)釋放內(nèi)存鲤嫡。
二送挑、 軟引用(SoftReference)
軟引用是用來(lái)描述一些有用但并不是必需的對(duì)象,在Java中用java.lang.ref.SoftReference類來(lái)表示暖眼。只有在內(nèi)存不足的時(shí)候JVM才會(huì)回收該對(duì)象惕耕。
如下:
Stringstr=newString("abc");// 強(qiáng)引用
SoftReference<String> softRef=new SoftReference<String>(str);// 軟引用
當(dāng)內(nèi)存不足時(shí),等價(jià)于:
If(JVM.內(nèi)存不足()){
str=null;// 轉(zhuǎn)換為軟引用
System.gc();// 垃圾回收器進(jìn)行回收
}
因此诫肠,這一點(diǎn)可以很好地用來(lái)解決OOM的問(wèn)題司澎,并且這個(gè)特性很適合用來(lái)實(shí)現(xiàn)緩存:比如網(wǎng)頁(yè)緩存、圖片緩存等栋豫。
在瀏覽頁(yè)面時(shí)挤安,我們會(huì)經(jīng)常使用回退功能,通常有兩種程序?qū)崿F(xiàn)方式:
(1)將用戶的過(guò)去查看過(guò)的用戶信息保存在內(nèi)存中丧鸯,每個(gè)存儲(chǔ)用戶信息的Java對(duì)象的生命周期貫穿整個(gè)應(yīng)用程序的始終蛤铜;缺陷:這樣會(huì)造成內(nèi)存的大量浪費(fèi),甚至?xí)斐蓛?nèi)存溢出丛肢。
(2)如果一個(gè)頁(yè)面瀏覽結(jié)束围肥,就對(duì)其進(jìn)行內(nèi)容的回收,只存儲(chǔ)當(dāng)前頁(yè)面的用戶信息蜂怎,當(dāng)用戶進(jìn)行回退操作時(shí)穆刻,重新構(gòu)建該用戶信息;缺陷:即使垃圾收集線程還沒(méi)有進(jìn)行垃圾收集杠步,存儲(chǔ)用戶信息的對(duì)象仍然完好地保存在內(nèi)存中氢伟,應(yīng)用程序也要重新構(gòu)建一個(gè)對(duì)象。
注:我們大都知道幽歼,訪問(wèn)磁盤(pán)文件朵锣、訪問(wèn)網(wǎng)絡(luò)資源、查詢數(shù)據(jù)庫(kù)等操作都是影響應(yīng)用程序執(zhí)行性能的重要因素试躏,如果能重新獲取那些尚未被回收的Java對(duì)象的引用猪勇,必將減少不必要的訪問(wèn),大大提高程序的運(yùn)行速度颠蕴。
因此看一下使用軟引用如何解決該問(wèn)泣刹,如下瀏覽器網(wǎng)頁(yè)緩存實(shí)例:
Browserprev=newBrowser();// 獲取頁(yè)面進(jìn)行瀏覽
SoftReferencesr=newSoftReference(prev);// 瀏覽完畢后置為軟引用
if(sr.get()!=null){
rev=(Browser)sr.get();// 還沒(méi)有被回收器回收助析,直接獲取
}else{
prev=newBrowser();// 由于內(nèi)存吃緊,軟引用對(duì)象被回收
sr=newSoftReference(prev);// 重新構(gòu)建
}
軟引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用椅您,如果軟引用所引用的對(duì)象被垃圾回收器回收外冀,Java虛擬機(jī)就會(huì)把這個(gè)軟引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。
三掀泳、弱引用(WeakReference)
只具有弱引用的對(duì)象擁有更短暫的生命周期雪隧。在垃圾回收器線程掃描它所管轄的內(nèi)存區(qū)域的過(guò)程中,一旦發(fā)現(xiàn)了只具有弱引用的對(duì)象员舵,不管當(dāng)前內(nèi)存空間足夠與否脑沿,都會(huì)回收它的內(nèi)存。不過(guò)马僻,由于垃圾回收器是一個(gè)優(yōu)先級(jí)很低的線程庄拇,因此不一定會(huì)很快發(fā)現(xiàn)那些只具有弱引用的對(duì)象。
// 創(chuàng)建一個(gè)引用隊(duì)列
ReferenceQueue<String>rq=new ReferenceQueue<String>();// 實(shí)現(xiàn)一個(gè)弱引用韭邓,將強(qiáng)引用類型hello和是實(shí)例化的rq放到弱引用實(shí)現(xiàn)里面
WeakReference<String>sr=new WeakReference<String>(newString("hello"),rq);// 通過(guò)弱引用get方法獲取強(qiáng)引用中創(chuàng)建的內(nèi)存空間hello值
System.out.println(sr.get());
System.gc();//通知JVM的gc進(jìn)行垃圾回收
System.out.println(sr.get());
四措近、 虛引用(PhantomReference)
虛引用也稱為幻影引用,一個(gè)對(duì)象是都有虛引用的存在都不會(huì)對(duì)生存時(shí)間都構(gòu)成影響女淑,也無(wú)法通過(guò)虛引用來(lái)獲取對(duì)一個(gè)對(duì)象的真實(shí)引用瞭郑。唯一的用處:能在對(duì)象被GC時(shí)收到系統(tǒng)通知,JAVA中用PhantomReference來(lái)實(shí)現(xiàn)虛引用
虛引用必須和引用隊(duì)列 (ReferenceQueue)聯(lián)合使用鸭你。當(dāng)垃圾回收器準(zhǔn)備回收一個(gè)對(duì)象時(shí)屈张,如果發(fā)現(xiàn)它還有虛引用,就會(huì)在回收對(duì)象的內(nèi)存之前苇本,把這個(gè)虛引用加入到與之 關(guān)聯(lián)的引用隊(duì)列中袜茧。
程序可以通過(guò)判斷引用隊(duì)列中是否已經(jīng)加入了虛引用,來(lái)了解被引用的對(duì)象是否將要被垃圾回收瓣窄。如果程序發(fā)現(xiàn)某個(gè)虛引用已經(jīng)被加入到引用隊(duì)列,那么就可以在所引用的對(duì)象的內(nèi)存被回收之前采取必要的行動(dòng)纳鼎。
轉(zhuǎn)自:? http://www.reibang.com/p/c3f3ecf98a6e