GC是垃圾收集的意思(Garbage Collection),內存處理是編程人員容易出現問題的地方,忘記或者錯誤的內存回收會致使程序或系統的不穩定甚至崩潰,Java提供的GC功能能夠自動監測對象是否超過做用域從而達到自動回收內存的目的。java
.NET的垃圾回收採用引用計數,java的垃圾回收機制採起的是有向圖的方式來實現,具體的說,java程序中的每一個線程對象就能夠看做是一個有向圖的起點,有向邊從棧中的引用者指向堆中的引用對象。在這個有向圖中,若是一個對象和根節點之間是可達的,那麼這個對象就是有效的,反之,這個對象就是能夠被回收的。採起這樣一種機制的優勢是能夠有效的避免循環引用。程序員
當程序員建立對象時,GC就開始監控這個對象的地址、大小以及使用狀況。經過有向圖機制肯定哪些對象是"可達的",哪些對象是"不可達的".當GC肯定一些對象爲"不可達"時,GC就有責任回收這些內存空間。算法
1) 在Young Generation中,有一個叫Eden Space的空間,主要是用來存放新生的對象,還有兩個Survivor Spaces(from、to),它們的大小老是同樣,它們用來存放每次垃圾回收後存活下來的對象。數據庫
2) 在Old Generation中,主要存放應用程序中生命週期長的內存對象。編程
3) 在Young Generation塊中,垃圾回收通常用Copying的算法,速度快。每次GC的時候,存活下來的對象首先由Eden拷貝到某個SurvivorSpace,當Survivor Space空間滿了後,剩下的live對象就被直接拷貝到OldGeneration中去。所以,每次GC後,Eden內存塊會被清空。安全
4) 在Old Generation塊中,垃圾回收通常用mark-compact的算法,速度慢些,但減小內存要求。性能優化
5) 垃圾回收分多級,0級爲所有(Full)的垃圾回收,會回收OLD段中的垃圾;1級或以上爲部分垃圾回收,只會回收Young中的垃圾,內存溢出一般發生於OLD段或Perm段垃圾回收後,仍然無內存空間容納新的Java對象的狀況。網絡
protected void finalize() { main.ref=this; // 恢復本對象,讓本對象可達 }
調用時間不肯定——有資源浪費的風險函數
若是把某些稀缺資源放到finalize()中釋放,可能會致使該稀缺資源等上好久好久之後才被釋放。形成資源的浪費!另外,某些類對象所攜帶的資源(好比某些JDBC的類)可能自己就很耗費內存,這些資源的延遲釋放會形成很大的性能問題。性能
可能不被調用——有資源泄漏的風險
在某些狀況下,finalize()壓根兒不被調用。好比在JVM退出的當口,內存中那些對象的finalize函數可能就不會被調用了。
所以一些清理工做如文件的關閉,鏈接的關閉等不要放到finalize函數中,要在程序中單獨進行管理,通常finalize只作C/C++內存的回收。
1.靜態集合類造成的對象引用
Static Vector v = new Vector(); for (int i = 1; i<100; i++) { Object o = new Object(); v.add(o); o = null; }
2.當集合裏面的對象屬性被修改後,再調用remove()方法時不起做用
3.各類鏈接,數據庫鏈接,網絡鏈接,IO鏈接等,顯示調用close關閉後才能被GC回收
強引用就是平時最經常使用的引用,當內存空間不足,Java虛擬機寧願拋出OutOfMemoryError錯誤,使程序異常終止,也不會靠隨意回收具備強引用的對象來解決內存不足的問題。
若是一個對象只具備軟引用,則內存空間足夠,垃圾回收器就不會回收它;若是內存空間不足了,就會回收這些對象的內存。
只具備弱引用的對象擁有更短暫的生命週期。在垃圾回收器線程掃描它所管轄的內存區域的過程當中,一旦發現了只具備弱引用的對象,無論當前內存空間足夠與否,都會回收它的內存。
虛引用,這種引用不經常使用,主要用途是結果引用關聯對象,實現對對象引用關係追蹤。虛引用並不會決定對象的生命週期。若是一個對象僅持有虛引用,那麼它就和沒有任何引用同樣,在任什麼時候候均可能被垃圾回收器回收。
幾種引用分別位於java.lang.ref.SoftReference; java.lang.ref.WeakReference; 和 java.lang.ref.PhantomReference;
String s = new String("abc") ; 在編譯階段在文字池中建立「abc」對象,運行new時,將pool中的對象複製一份放到heap中,而且把heap中的這個對象的引用交給s持有,所以這條語句建立了2個String對象。
String s1 = new String("abc") ; String s2 = new String("abc") ; 共建立三個對象,pool中一個,heap中2個。
句柄能夠不依賴於對象而存在,例如String s,建立了句柄s,在棧中保存,但並無任何對象相關聯。句柄能夠考慮爲遙控器,對象爲電視,擁有了遙控器,就能夠操控電視,可是沒有電視,同樣能夠有遙控器。
因爲字符串對象的大量使用(它是一個對象,通常而言對象老是在heap分配內存),Java中爲了節省內存空間和運行時間,在編譯階段就把全部的字符串文字放到一個文字池(pool of literal strings)中,而運行時文字池成爲常量池的一部分。文字池的好處,就是該池中全部相同的字符串常量被合併,只佔用一個空間。因此上述的 "abc" 只佔一份空間。
String s1 = "abc" ;
String s2 = "abc" ;
這裏 s1 == s2 成立
String s1 = new String("abc") ;
String s2 = new String("abc") ;
這裏 s1 == s2 不成立,s1.equals(s2)成立
Java語言規範沒有明確地說明JVM使用哪一種垃圾回收算法,可是任何一種垃圾收集算法通常要作2件基本的事情:(1)發現無用信息對象;(2)回收被無用對象佔用的內存空間,使該空間可被程序再次使用。
大多數垃圾回收算法使用了根集(root set)這個概念;所謂根集就量正在執行的Java程序能夠訪問的引用變量的集合(包括局部變量、參數、類變量),程序可使用引用變量訪問對象的屬性和調用對象的方法。垃圾收集首選須要肯定從根開始哪些是可達的和哪些是不可達的,從根集可達的對象都是活動對象,它們不能做爲垃圾被回收,這也包括從根集間接可達的對象。而根集經過任意路徑不可達的對象符合垃圾收集的條件,應該被回收。下面介紹幾個經常使用的算法。
一、 引用計數法(Reference Counting Collector)
引用計數法是惟一沒有使用根集的垃圾回收的法,該算法使用引用計數器來區分存活對象和再也不使用的對象。通常來講,堆中的每一個對象對應一個引用計數器。當每一次建立一個對象並賦給一個變量時,引用計數器置爲1。當對象被賦給任意變量時,引用計數器每次加1當對象出了做用域後(該對象丟棄再也不使用),引用計數器減1,一旦引用計數器爲0,對象就知足了垃圾收集的條件。
基於引用計數器的垃圾收集器運行較快,不會長時間中斷程序執行,適宜地必須 實時運行的程序。但引用計數器增長了程序執行的開銷,由於每次對象賦給新的變量,計數器加1,而每次現有對象出了做用域生,計數器減1。
二、tracing算法(Tracing Collector)
tracing算法是爲了解決引用計數法的問題而提出,它使用了根集的概念。基於tracing算法的垃圾收集器從根集開始掃描,識別出哪些對象可達,哪些對象不可達,並用某種方式標記可達對象,例如對每一個可達對象設置一個或多個位。在掃描識別過程當中,基於tracing算法的垃圾收集也稱爲標記和清除(mark-and-sweep)垃圾收集器.
三、compacting算法(Compacting Collector)
爲了解決堆碎片問題,基於tracing的垃圾回收吸取了Compacting算法的思想,在清除的過程當中,算法將全部的對象移到堆的一端,堆的另外一端就變成了一個相鄰的空閒內存區,收集器會對它移動的全部對象的全部引用進行更新,使得這些引用在新的位置能識別原來 的對象。在基於Compacting算法的收集器的實現中,通常增長句柄和句柄表。
四、copying算法(Coping Collector)
該算法的提出是爲了克服句柄的開銷和解決堆碎片的垃圾回收。它開始時把堆分紅 一個對象 面和多個空閒面, 程序從對象面爲對象分配空間,當對象滿了,基於coping算法的垃圾 收集就從根集中掃描活動對象,並將每一個 活動對象複製到空閒面(使得活動對象所佔的內存之間沒有空閒洞),這樣空閒面變成了對象面,原來的對象面變成了空閒面,程序會在新的對象面中分配內存。
一種典型的基於coping算法的垃圾回收是stop-and-copy算法,它將堆分紅對象面和空閒區域面,在對象面與空閒區域面的切換過程當中,程序暫停執行。
五、generation算法(Generational Collector)
stop-and-copy垃圾收集器的一個缺陷是收集器必須複製全部的活動對象,這增長了程序等待時間,這是coping算法低效的緣由。在程序設計中有這樣的規律:多數對象存在的時間比較短,少數的存在時間比較長。所以,generation算法將堆分紅兩個或多個,每一個子堆做爲對象的一代(generation)。因爲多數對象存在的時間比較短,隨着程序丟棄不使用的對象,垃圾收集器將從最年輕的子堆中收集這些對象。在分代式的垃圾收集器運行後,上次運行存活下來的對象移到下一最高代的子堆中,因爲老一代的子堆不會常常被回收,於是節省了時間。
六、adaptive算法(Adaptive Collector)
在特定的狀況下,一些垃圾收集算法會優於其它算法。基於Adaptive算法的垃圾收集器就是監控當前堆的使用狀況,並將選擇適當算法的垃圾收集器。
參考:
http://blog.csdn.net/program_think/article/details/4302366 編程隨想 Java性能優化[4]:關於finalize函數
http://developer.51cto.com/art/201103/248642.htm 詳解Java GC的工做原理
http://tech.qq.com/a/20060726/000329.htm 全面分析Java的垃圾回收機制