垃圾收集java
程序計數器、虛擬機棧、本地方法棧三個區域隨線程而生,隨線程而滅;這幾個區域的內存分配和回收都具有穩定性,不須要過多的考慮回收的問題。而Java堆和方法區則不同。算法
Java堆中存儲了幾乎全部的對象實例,垃圾收集器進行對堆的回收以前,須要判斷這些對象是否還存活函數
一。判斷對象是否存活線程
判斷對象是否還活着,主要有兩種方法代理
1.引用計數法對象
給對象添加一個引用計數器,每當一個地方引用時,計數器值加1;內存
每當一個引用失效時,計數器減1;資源
任何計數器爲0的對象爲不可能被使用的對象。虛擬機
優勢:實現簡單,斷定效率高 效率
缺點:很難解決對象之間的相互循環引用的問題
2.可達性分析法
主流的實現中,都是經過可達性分析法來斷定對象是否存活。
該算法基本思想:經過一系列稱爲「GC Roots」的對象做爲起始點,從這些節點開始向下搜索,搜索的路徑稱爲引用鏈;
當一個對象到GC Roots沒有任何引用鏈相連時(即GC Roots沒法到達該對象),稱爲不可達對象,該對象不可用
此時,能夠斷定該對象是可回收的對象。
Java中能夠做爲GC Roots的對象包括如下四種:
(1)虛擬機棧中引用的對象
(2)方法區中類靜態屬性引用的對象
(3)方法區中常量引用的對象
(4)本地方法棧中JNI(通常說的是Native方法)引用的對象
3.方法區的回收
因爲方法區中主要存放的是永久代對象,所以,方法區中進行垃圾收集的性價比通常較低。
永久代的垃圾回收主要分爲兩類:1.廢棄常量 2.無用的類
類的卸載條件比較苛刻,須要同時知足如下三個條件:
(1)該類的全部實例已經被回收,即Java堆中不存在該類的任何實例
(2)加載該類的ClassLoader(即類加載器)已被回收
(3)該類對應的java.lang.Class對象沒有在任何地方唄引用,沒法在任何地方經過反射訪問該類的方法
在大量使用動態代理、反射的場景,須要虛擬機具有卸載類的功能,以保證永久代不會形成內存溢出
4.finalize()
相似 C++ 的析構函數,用於關閉外部資源。
但 try-finally 等方式能夠作得更好,而且該方法運行代價很高,不肯定性大,沒法保證各個對象的調用順序,所以最好不要使用。
當一個對象可被回收時,且被斷定爲有必要執行該對象的 finalize() 方法,那麼可能讓該對象自救(只須要從新與引用鏈上的任何一個對象創建關係便可)。
自救只能進行一次,若是回收的對象以前調用了 finalize() 方法自救,後面回收時不會再調用該方法。
二。強引用與軟引用
Java對引用的概念分爲四種,從強到弱依次爲:強引用,軟引用,弱引用,虛引用
1.強引用
代碼中廣泛存在的相似 Object obj = new Object()這種,只要強引用在,該對象永遠不會被回收
2.軟引用
用來描述一些還有用但非必須的對象;提供了SoftReference類來實現軟引用
在系統發生內存溢出異常以前,會把這些對象列入回收範圍之中,進行第二次回收
3.弱引用
也是用來描述非必須對象,可是比軟引用更弱;提供了WeakReference類來實現
弱引用關聯的對象,只能生存到下一次垃圾收集發生以前。
當垃圾收集器工做時,不管當前內存是否足夠,都會回收掉只被弱引用關聯的對象。
4.虛引用
最弱的引用關係;提供PhantomReference類實現
一個對象是否有虛引用的存在徹底不會對其生存時間產生影響,同時也沒法經過虛引用來取得一個對象的實例。
設置虛引用的惟一目的是,經過虛引用在這個對象被回收時收到一個系統通知