天天看點

JVM之:GC算法和GC收集器

一、前言

JVM是Java virtual machine 的縮寫,簡稱:java虛拟機。它是整個java實作跨平台的最核心的部分,所有的java程式會首先被編譯為.class的類檔案,而解釋和執行這種跨平台的.class檔案的就是java虛拟機。

二、簡介

而java與其他程式設計語言(c/c++)等,最大的不同之處也是優勢之處:java不需要開發人員自己編寫代碼來釋放和回收記憶體。而把這項任務交由java虛拟機自行處理,就是通常我們所說的GC回收。gc回收的工作在java裡是由jvm自行負責的,編寫和開發jdk的偉大工程師們把其底層所有的工作處理邏輯都安排的非常完美。GC回收機制,通常又涉及運作時記憶體區、GC算法、GC收集器等。

三、運作時記憶體區

java運作時資料區,簡單概括包括了:方法區、堆、虛拟機棧、本地方法棧和程式計數器等。詳細的各個區域的原理和講解參考另一篇文章

                                                     深入了解java虛拟機

  • 方法區:是線程共享的記憶體區域,用來存儲類加載的資訊、常量、靜态變量、即時編譯器編譯後的代碼等。其中方法區中還有個經常會用到的區域叫做運作時常量池,主要用于存儲一些常量,當建立一個常量時,首先會在運作時常量池檢視是否有,有則直接使用,否則重新建立。
  • 堆:堆是最大的一塊記憶體區域,也是垃圾回收管理的主要區域,主要用于存放對象執行個體。
  • 虛拟機棧:虛拟機棧主要存儲基本資料類型變量和引用類型變量。其中與堆的差別就是如:Obj obj=new Object();等号左邊則是在虛拟機棧上配置設定棧區存儲引用類型變量的句柄Obj obj,等号右邊則是存儲對象執行個體,棧區的句柄是指向堆區的對象執行個體的,一般通過句柄通路堆區的對象執行個體。
  • 本地方法棧:與虛拟機棧意義相似,差別在于虛拟機棧用于使Java方法,而本地方法棧則是針對于Native方法服務。
  • 程式計時器:線程私有的,每個線程都會配置設定一個線程計時器,用來表示目前線程執行的位元組碼的行号訓示器。在多線程中,一個線程執行的時候釋放鎖,另一個線程執行完,再回來執行前面線程的時候,就是通過程式計時器來擷取繼續執行的位置。
JVM之:GC算法和GC收集器

jvm運作時資料區

四、記憶體配置設定和回收政策

下圖所示是堆中記憶體配置設定示意圖,建立一個對象,首先會在eden區域配置設定區域,如果記憶體不夠,就會将年齡大的轉移到Survivor區,當survivor區域存儲不下,則會轉移年老代的。對于一些靜态變量不需要使用對象,直接調用的,則會被放入永生代。一般來說長期存活的對象最終會被存放到年老代,還有一種特殊情況也會被存放到年老代,就是建立大對象時,比如資料這種需要申請連續空間的,如果空間比較大的,則會直接進入年老代。

JVM之:GC算法和GC收集器

記憶體配置設定示意圖

在回收過程中,有一個參數比較重要,就是對象的年齡,如果在一次垃圾回收過程中有使用該對象的,則将對象年齡加1,否則減1,當計數為0,則進行回收,如果年齡達到一定數字則進入老生代。總的來說記憶體配置設定機制主要展現在對象建立之後是否仍在使用,已經不使用的則回收,繼續使用的則對其年齡進行更新,達到一定程度,轉移到年老代。

五、GC回收算法

1.标記-清除算法

        該算法先标記,後清除,将所有需要回收的算法進行标記,然後清除;這種算法的缺點是:效率比較低;标記清除後會出現大量不連續的記憶體碎片,這些碎片太多可能會使存儲大對象會觸發GC回收,造成記憶體浪費以及時間的消耗。

2.複制算法

        複制算法将可用的記憶體分成兩份,每次使用其中一塊,當這塊回收之後把未回收的複制到另一塊記憶體中,然後把使用的清除。這種算法運作簡單,解決了标記-清除算法的碎片問題,但是這種算法代價過高,需要将可用記憶體縮小一半,對象存活率較高時,需要持續的複制工作,效率比較低。

3.标記整理算法

        标記整理算法是針對複制算法在對象存活率較高時持續複制導緻效率較低的缺點進行改進的,該算法是在标記-清除算法基礎上,不直接清理,而是使存活對象往一端遊走,然後清除一端邊界以外的記憶體,這樣既可以避免不連續空間出現,還可以避免對象存活率較高時的持續複制。這種算法可以避免100%對象存活的極端狀況,是以老年代不能直接使用該算法。

4.分代收集算法

         分代收集算法就是目前虛拟機使用的回收算法,它解決了标記整理不适用于老年代的問題,将記憶體分為各個年代,在不同年代使用不同的算法,進而使用最合适的算法,新生代存活率低,可以使用複制算法。而老年代對象存活率搞,沒有額外空間對它進行配置設定擔保,是以隻能使用标記清除或者标記整理算法。

六、垃圾收集器

  • Serial收集器

jdk1.3之前唯一新生代收集唯一選擇,最基本、發展曆史最悠久的收集器,單線程的收集器;當它進行垃圾回收的時候,必須暫停其他所有工作的線程直至它的垃圾收集工作結束Stop The World“”。

  • parNew收集器

parNew是Serial收集器的多線程版本,除了使用多條線程進行垃圾收集之外,其餘行為均與Serial相同。Server模式下的虛拟機中首選的新生代收集器,目前唯一能與CMS收集器配合工作的。

  • parallel scavenge收集器

parallel scavenge是一個新生代收集器,使用了複制的算法;并行多線程的收集器。它的目标是達到一個可控制的吞吐量(吞吐量 = 運作代碼時間 / 垃圾收集時間)。一般來說,吞吐量越高,标明程式性能越好;

  • serial old收集器

Serial Old是Serial收集器的老年代版本,也是單線程收集器。使用“标記—整理”算法,作為CMS收集器的後備預案,在并發收集發生Concurrent Mode Failure時使用。

  • parallel old收集器

parallel old是parallel scavenge收集器的老年代版本,使用多線程和“标記—整理”算法。jdk1.6才開始提供。

  • cms收集器

cms收集器是一種以擷取最短回收停頓時間為目标的收集器,多集中用于網際網路網站或B/S架構的服務端上,重視服務的響應速度,希望系統停頓時間短,使用者體驗好。使用“标記—清除”算法:

   初始标記

   并發标記

   重新标記

   并發清除

  • g1收集器

g1收集器是當今收集器技術最前沿的成果之一,jdk1.7的重要進化特征。面向服務端的垃圾收集器;它有如下特征:

并行與并發、分代收集、空間整合、可預測的停頓。

    初始标記

    并發标記

    最終标記

    篩選回收

JVM之:GC算法和GC收集器

同名原創公衆号: 程式大視界

繼續閱讀