深刻理解Java虛擬機閱讀心得(二)

垃圾收集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類實現

    一個對象是否有虛引用的存在徹底不會對其生存時間產生影響,同時也沒法經過虛引用來取得一個對象的實例。

    設置虛引用的惟一目的是,經過虛引用在這個對象被回收時收到一個系統通知

相關文章
相關標籤/搜索