深入理解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類實現

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

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

原文地址https://www.cnblogs.com/xiang9286/p/10542874.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章