JAVA 垃圾回收機制(一) --- 對象回收與算法初識

##JAVA 垃圾回收機制(一) — 對象回收與算法初識

一、概念

這裏說的GC回收,指的是 Java 堆的地方, 深入Java虛擬機之 — JVM的愛恨情仇 文章 中,我們知道了程序計算器,虛擬機棧和本地方法棧都是隨線程開啓,隨線程關閉的,因此這幾塊區域的內存分配和回收都具備確定性。而Java 堆和方法區則不一樣,一個接口中的多個實現類需要的內存可能不一樣,一個方法中的多個分支需要的內存也可能不一樣,只有程序在運行時,才知道創建了哪些對象,這部分內存的分配和回收都是動態的,垃圾收集器所關注的就是這部分內存。
而 GC 關注的也就3個點:

  • 哪些對象需要回收
  • 什麼時候回收
  • 如何回收

二、哪些對象需要回收

怎麼判斷對象是“存活” 的,還是已經"死亡"呢?主要有以下方法:

  • 1.引用計算算法: 給對象添加一個引用計算器,每當有一個地方引用它,則加1,當引用失效,則減1;任何時刻計算器爲0的對象就是不可能再被使用的。但它很難解決對象之間相互循環引用的問題,所以主流的Java虛擬機都沒有采用這種算法。
  • 2.可達性分析算法:
    通過一系列的 “GC Roots” 的對象作爲起始點,從這些起始點開始向下搜索,搜索走過的路徑被稱爲引用鏈(Reference Chain),當一個對象到GC Roots 沒有任何引用鏈項鍊,即GC Roots 不可達,則證明此對象是不可用的。

三、什麼時候回收

  • 1.在可達性分析算法不可達的對象,也不一定"非死不可’,它會經歷兩次標記,一是當不可達 GC Roots 時,標記一次並篩選,篩選的條件是該對象是否有必要執行 finalize 方法。當對象沒有覆蓋 finalize 方法,或者已經執行過 finalize 方法時,則認爲此對象會被回收。
  • 2.上面都是對 Java 堆進行回收,雖說 Java 堆 可以回收70%~95%的空間,但方法區同樣可以回收一些資源,方法區主要回收兩個部分廢棄常量和無用的類。

四、如何回收

  • 4.1 標記-清除算法
    這個算法首先標記處所有需要回收的對象,在標記完成之後統一回收所有被標記的對象。
    看似美好,實則不然,主要有以下兩個缺點:
    效率問題:標記和清除兩個效率都不高
    空間問題:標記清除後,會產生大量空間碎片,在大對象需要分配空間時,找不到內存,從而又觸發 GC 操作。

  • 4.2 複製算法
    基於 標記-清除算法的效率問題,複製算法出現的。
    這種算法是把內存分爲相等的兩塊,一塊用來存儲對象,當GC操作後,把還存留的對象移動到未存對象的那塊內存區域,再把使用過的內存清掉。這樣每次都對整個半區進行內存回收,就不用擔心內存碎片的問題了。

  • 4.3 標記-整理算法
    標記整理算法,是針對老年代的。它與標記-清除算法一樣,但不是對相對進行清除,而是移動到另一端,分兩個步驟
    1.標記那些被引用的對象
    2.將被標記的對象移動按順序移動到一端,然後清除掉可回收的對象

  • 4.4、分代收集算法
    在商業的虛擬機中,都採用 分代收集算法,根據對象存活週期將內存劃分爲幾塊,即新生代和老年代;
    在新生代中,每次都有大量對象死去,只有少量活着,就選用複製算法;而老年代的對象存活率比較高,沒有額外空間對它進行分配擔保,就必須使用 “標記-整理”或者“標記-清理” 進行回收。

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