對象在內存中分爲三種狀態:緩存
可達狀態ide
一個對象建立之後,有一個或者多個引用變量引用該對象,那麼這個對象屬於可達狀態性能
可恢復狀態ui
若是程序中某個對象再也不有任何引用變量引用它,他將進入可恢復狀態,此時從有向圖的起始頂點不能導航到該對象。在這種狀態下,系統的垃圾回收機制轉變回收該對象所佔用的內存。在回收該對象以前,系統會調用可恢復狀態的對象的finalize方法進行資源清理,若是系統調用finalize方法從新讓一個以上的引用變量引用該對象,則該對象會再次變成可達狀態;不然,該對象將進入不可達狀態。this
不可達狀態spa
當對象的全部關聯都被切斷,且系統調用全部對象的finalize方法依然沒有使該對象變成可達狀態後,這個對象將永久性地失去引用,最後變成不可達狀態。只有當一個對象出於不可達狀態,系統纔會真正回收該對象所佔用的資源。.net
對象狀態轉化圖線程
finalize方法指針
垃圾回收對象內存以前會先調用finalize方法,這個是object中的方法,注意有可能失去引用的某個對象只是佔了少許內存,並且系統也沒有嚴重內存需求,所以垃圾回收機制沒有試圖回收該對象佔用資源,因此finalize方法也不會執行。code
protected void finalize() throws Throwable
有以下幾個特色:
1 不要主動調用某個對象的finalize方法,應該由垃圾回收機制調用。
2 finalize什麼時候被調用不肯定,不要認爲必定能夠執行。
3 執行finalize方法時,可讓該對象轉又化爲可達狀態。
4 當執行finalize方法時,出線異常,不會報告異常,繼續執行。
public class FinalizeTest {
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalize");
ft=this;
}
public void print(){
System.out.println("print");
}
static FinalizeTest ft=null;
/**
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
new FinalizeTest();
System.gc();
//Thread.sleep(2000); 1
//System.runFinalization(); 2
ft.print();
}
}
這樣會有空指針異常
1 去掉1的註釋,註釋2不去掉,就不會有異常,是由於垃圾回收機制調用了finalize方法,使得ft引用指向了該對象,該線程睡2秒鐘就是爲了等待垃圾回收機制回收該對象,調用finalize方法,
在該方法ft引用到對象,不會有空指針異常。
2 去掉2的註釋,註釋1不去掉,也不會有異常,由於強制垃圾回收機制調用可恢復對象的finalize方法
對象有四種引用
強引用
建立一個對象,把這個對象賦予引用變量,就是強引用,若是一個對象具備強引用,那就 相似於必不可少的生活用品,垃圾回收器毫不會回收它。當內存空 間不足,Java虛擬機寧願拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具備強引用的對象來解決內存不足問題。
軟引用SoftReference
若是一個對象只具備軟引用,那就相似於無關緊要的生活用品。若是內存空間足夠,垃圾回收器就不會回收它,若是內存空間不足了,就會回收這些對象的內存。只要垃圾回收器沒有回收它,該對象就能夠被程序使用。軟引用可用來實現內存敏感的高速緩存。
軟引用能夠和一個引用隊列(ReferenceQueue)聯合使用,若是軟引用所引用的對象被垃圾回收,Java虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。
弱引用WeakReference
若是一個對象只具備弱引用,那就相似於無關緊要的生活用品。 弱引用與軟引用的區別在於:只具備弱引用的對象擁有更短暫的生命週期。在垃圾回收器線程掃描它 所管轄的內存區域的過程當中,一旦發現了只具備弱引用的對象,無論當前內存空間足夠與否,都會回收它的內存。不過,因爲垃圾回收器是一個優先級很低的線程, 所以不必定會很快發現那些只具備弱引用的對象。
弱引用能夠和一個引用隊列(ReferenceQueue)聯合使用,若是弱引用所引用的對象被垃圾回收,Java虛擬機就會把這個弱引用加入到與之關聯的引用隊列中。
需引用PhantomReference
"虛引用"顧名思義,就是形同虛設,與其餘幾種引用都不一樣,虛引用並不會決定對象的生命週期。若是一個對象僅持有虛引用,那麼它就和沒有任何引用同樣,在任什麼時候候均可能被垃圾回收。
虛引用主要用來跟蹤對象被垃圾回收的活動。虛引用與軟引用和弱引用的一個區別在於:虛引用必須和引用隊列(ReferenceQueue)聯合使用。當垃 圾回收器準備回收一個對象時,若是發現它還有虛引用,就會在回收對象的內存以前,把這個虛引用加入到與之關聯的引用隊列中。程序能夠經過判斷引用隊列中是 否已經加入了虛引用,來了解
被引用的對象是否將要被垃圾回收。程序若是發現某個虛引用已經被加入到引用隊列,那麼就能夠在所引用的對象的內存被回收以前採起必要的行動。
建立一個強引用
String str =new String ("hello");
建立一個引用隊列
ReferenceQueue rq=new ReferenceQueue();
建立一個弱引用,並關聯引用隊列
WeakReference wr=new WeakReference(str,rq);
關係圖以下:
String str=new String("hello");
ReferenceQueue rq=new ReferenceQueue();
WeakReference wr=new WeakReference(str,rq);
System.out.println(wr.get());
System.out.println(rq.poll()==wr);
str=null;
System.gc();
System.runFinalization();
System.out.println(wr.get());
System.out.println(rq.poll()==wr);
輸出
hello
false
null
true
垃圾回收的時候,弱引用會加入到關聯的隊列中,因此最後輸出true。
如下爲摘抄的一段軟引用的例子 來自於(http://blog.csdn.net/arui319/article/details/8489451)
假設咱們的應用會用到大量的默認圖片,好比應用中有默認的頭像,默認遊戲圖標等等,這些圖片不少地方會用到。若是每次都去讀取圖片,因爲讀取文件須要硬件操做,速度較慢,會致使性能較低。因此咱們考慮將圖片緩存起來,須要的時候直接從內存中讀取。可是,因爲圖片佔用內存空間比較大,緩存不少圖片須要不少的內存,就可能比較容易發生OutOfMemory異常。這時,咱們能夠考慮使用軟引用技術來避免這個問題發生。
首先定義一個HashMap,保存軟引用對象。
private Map<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>(); |
再來定義一個方法,保存Bitmap的軟引用到HashMap。
public void addBitmapToCache(String path) { // 強引用的Bitmap對象 Bitmap bitmap = BitmapFactory.decodeFile(path); // 軟引用的Bitmap對象 SoftReference<Bitmap> softBitmap = new SoftReference<Bitmap>(bitmap); // 添加該對象到Map中使其緩存 imageCache.put(path, softBitmap); }
|
獲取的時候,能夠經過SoftReference的get()方法獲得Bitmap對象。
public Bitmap getBitmapByPath(String path) { // 從緩存中取軟引用的Bitmap對象 SoftReference<Bitmap> softBitmap = imageCache.get(path); // 判斷是否存在軟引用 if (softBitmap == null) { return null; } // 取出Bitmap對象,若是因爲內存不足Bitmap被回收,將取得空 Bitmap bitmap = softBitmap.get(); return bitmap; } |
使用軟引用之後,在OutOfMemory異常發生以前,這些緩存的圖片資源的內存空間能夠被釋放掉的,從而避免內存達到上限,避免Crash發生。
須要注意的是,在垃圾回收器對這個Java對象回收前,SoftReference類所提供的get方法會返回Java對象的強引用,一旦垃圾線程回收該Java對象以後,get方法將返回null。因此在獲取軟引用對象的代碼中,必定要判斷是否爲null,以避免出現NullPointerException異常致使應用崩潰。