JVM筆記2:垃圾收集器

  • JVM的垃圾收集器(Garbage Collector)管理的是Java堆方法區的垃圾回收。
  • GC需要完成三件事:哪些內存需要回收(即判定垃圾)?什麼時候回收?如何回收(垃圾收集算法)?

垃圾判定算法

引用計數算法

  • 對指向對象的引用進行計數,當計數器值歸零時則刪除該對象。
  • 但是當出現循環引用時,相關的對象永遠無法被判定爲垃圾。

可達性分析算法

       該算法基本思路如下:

  • 選定一系列對象作爲根對象“GC Roots”,根據引用關係向下搜索,搜索走過的路徑稱爲“引用鏈”
  • 如果某個對象到“GC Roots”之間沒有任何引用鏈相連,則證明此對象是不可能再被使用的

       固定選爲“GC Roots”的對象有以下幾類:

  • 在虛擬機棧中引用的對象。(局部變量、臨時變量等)
  • 在方法區中類靜態變量和常量引用的對象
  • 在本地方法棧中JNI(即本地方法)引用的對象
  • JVM內部的引用
  • 所有被同步鎖持有的對象

       除此以外,不同的垃圾收集器還有自己的選擇。

引用的類型:無論哪一種垃圾判定算法都與引用有關,在JDK1.2版本之後擴充了引用的概念:

  • 強引用:即平時最常見的引用關係,有強引用的對象一定不會被回收
  • 軟引用:在首次回收後如果還沒有足夠的內存,纔會回收只有軟引用的對象(SoftReference類)
  • 弱引用:比軟引用更弱,在垃圾收集器開始工作時,無論內存是否足夠,只有弱引用的對象都會被回收(WeakReference類)
  • 虛引用:最弱的引用關係,甚至無法從虛引用獲取對象實例,更無法對對象的生存時間構成影響。(PhantomReference類)

垃圾收集算法

分代收集理論

       當前商業虛擬機的垃圾收集器大部分都基於“分代收集(Generational Collection)”的理論。分代收集理論基於以下假說:

  1. 弱分代假說(Weak Generational Hypothesis):絕大多數對象都是朝生夕滅的。
  2. 強分代假說(Strong Generational Hypothesis):熬過越多次垃圾收集過程的對象就越難以消亡。
  3. 跨代引用假說(Intergenerational Reference Hypothesis):跨代引用相對於同代引用來說僅佔極少數。

       基於以上假說的垃圾收集器會將其管理的內存劃分爲不同的區域,並根據各區域的特點以不同的頻率各自執行不同的垃圾收集算法。具體來說,至少會有“新生代(Young Generation)”和“老年代(Old Generation)”兩類區域。在新生代中,每次垃圾收集時都會有大批對象被回收,存活的少量對象會逐漸被移動到老年代中。據此可以總結以下特點:

  • 新生代中的大部分對象都很容易被回收,因此需要以較高的頻率執行垃圾收集算法;同時每次垃圾收集後的新生代區域中的對象會很稀疏。
  • 老年代中的大部分對象難以消亡,因此垃圾回收的頻率比較低;並且每次垃圾收集後會產生較小的碎片。

       因此在不同的區域中需要執行不同的垃圾收集算法。常見的垃圾收集算法有以下幾種。

標記-清除算法

  • 標記-清除(Mark-Sweep)算法是最早最基礎的垃圾收集算法(算法示意圖如下)
  • 過程:第一階段根據垃圾判定算法標記出需要回收(或需要存活)的對象;第二階段清除(或保留)被標記的對象。
  • 缺點:一是執行效率不穩定,容易隨着對象數量增長而降低;二是內存會產生較多的碎片,導致觸發過多不必要的GC動作。

sweep

標記-複製算法

半區複製,Semispace Copying

  • 過程:將內存分爲大小相等的兩半,每次只使用其中一半。當執行垃圾收集時,就把仍存活的對象依次複製到另一半,再把已使用過的一半直接清理掉。
  • 缺點:一是如果內存中多數對象是存活的,就會產生大量的複製開銷;二是可用內存縮小了一半。
    copying

Appel式回收

根據IBM一項研究,新生代中的對象98%都熬不過第一輪收集,因此並不需要按照半區複製中1:1的比例來劃分新生代的內存空間。

  • 爲了優化半區複製的空間代價,可以將新生代分爲一塊較大的Eden空間和兩塊較小的Survivor空間。每次分配內存只使用Eden和其中一塊Survivor,垃圾收集時將所有的存活對象複製到另一塊Survivor中,然後清理掉已使用的兩塊空間。
  • HotSpot虛擬機默認的Eden和Survivor大小比例爲8:1,即只有10%的空間是被浪費的。
  • 如果垃圾收集後有大於10%的對象存活,需要依賴其他內存區域(實際上大多就是老年代)保存多出來的存活對象。

標記-整理算法

  • 由於標記-複製算法需要其他內存區域的擔保,因此老年代不能直接用這種算法。標記-整理(Mark-Compact)算法就是針對老年代提出的。
  • 過程:標記階段後,讓所有存活的對象向內存空間的一端移動。
  • 缺點:與簡單的標記-清除算法比,移動操作有較重的負擔,會延長GC的延遲。(相應的,由於沒有碎片,內存分配會更加簡單)。
  • Compromise:在老年代上,平時多數時間都採用標記-清除算法;直到內存空間的碎片化程度已經大到影響對象分配時,在採用標記-整理算法收集一次以清理碎片。
    compact
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章