JVM學習筆記——GC概述

title: JVM學習筆記——GC概述
date: 2018/9/2 12:05:00
description: 最近開始着手JVM的學習,在這裏把本身學習過程當中的筆記分享出來,但願能幫到一些小夥伴,同時也是對本身的學習的一個梳理。java

GC概述

其實GC主要就是思考如下三件事情:算法

  • 哪些內存須要回收?
  • 何時回收?
  • 如何回收?

  • 哪些內存須要回收

    主要針對Java堆和方法區,程序計數器、虛擬機棧、本地方法棧內存分配與回收具備肯定性,因此不須要過多考慮GC的問題。
    其中方法區的回收主要針對如下兩種:
    • 回收常量
      沒有任何地方引用到該常量時,該常量將會被回收。
    • 回收無用類
      同時知足如下幾個條件則視爲「無用類」。
      • Java堆中不存在任何該類的實例
      • 加載該類的ClassLoader已經被回收
      • 該類的java.lang.Class對象沒有在任何地方被引用,沒法在任何地方經過反射訪問到該類。
  • 何時回收(判斷對象是否「死去」)

    • 引用計數算法
      爲對象增長一個引用計數器,每有一次引用則計數器+1,失去一個引用則計數器-1。這種算法效率很高,實現也很簡單,可是在相互引用的狀況下,會出現沒法回收的狀況。例如:a.instance = b; b.instance = a;
    • 可達性分析算法

      使用GC Roots做爲起始點,當一個對象到GC Roots沒有引用鏈路時(即不可達),則此時對象視爲「死亡」。此方法也是現有JVM中經常使用的算法。
      GC Roots包括下面幾種:學習

      • 虛擬機棧(棧幀中的本地變量表)中引用的對象
      • 本地方法棧中Native方法引用的對象
      • 方法區中類靜態屬性引用的對象
      • 方法區中常量引用的對象

      換句話來講,以上4中類型其實就是:類成員變量,類靜態變量,常量,局部變量,只要某個對象不被以上4種類型關聯到,那麼該對象就是「已死」的,gc時就會被回收內存空間。指針

  • 如何回收(垃圾收集算法)

    • 標記-清除算法(Mark-Sweep)
      Mark-Sweep
      它是最基礎的算法,後續的算法都是針對它的缺點改進而生。它存在兩個缺點:
      • 效率問題。標記與清除這兩個過程效率都不高。
      • 空間問題。如圖所示,清除後的內存空間是不規整的,會產生大量的內存碎片。大量的碎片會致使分配大對象時,找不到連續的內存空間而提早觸發另外一次GC。

    • 複製算法(Copying)

      Copying
      針對標記-清除的效率問題,複製算法將內存分爲兩塊空間,每次只使用其中一塊。當這塊的內存空間用完時,將存活的對象移到另外一塊中,而後將已使用的內存空間一次性清理掉。這樣作的好處是不會產生碎片,清除也是針對連續的空間作處理,只要移動堆指針就行。
      實際上在如今的虛擬機中,將這種算法應用在新生代。按照8:1:1的比例將內存分爲三塊,每次使用一塊較大的與較小的其中一塊,清理時將存活對象移到剩下的一塊中,這樣每次只會浪費10%的內存,因爲新生代中的內存通常都是「朝生夕死」的,使用這種算法能夠極大的提高效率。可是,不能保證每次清理時,剩下的一塊空間可以存放全部的存活對象,因此這裏會依賴其餘內存空間(通常指老年代)進行分配擔保(Handle Promotion)。code

    • 標記-整理算法(Mark-Compact)

      Mark-Compact
      複製算法在對象存活率較高時,效率就會變低,因此針對高對象存活率的狀況,就有人提出了該算法。標記的過程並無變化,但標記後並非進行「清除」,而是將存活的對象向一端進行移動整理,而後清除掉其他的空間。現代虛擬機常將這種算法在老年代中使用。對象

    • 分代收集算法(Generational Collection)

      分代收集算法是根據對象的存活時間,將內存劃分幾塊(通常分爲新生代和老年代),這樣就能夠根據不一樣的內存區域特色採用不一樣的算法。針對新生代,使用複製算法,用少許的內存空間換來更大的效率;針對老年代,使用標記-整理或標記-清除來處理。ip

相關文章
相關標籤/搜索