JavaGC機制詳解


參考文檔1參考文檔2參考文檔3

1 概述

在 Java中,對象實例都是在堆上創建。
方法區,又叫靜態成員區,所有的 1 類(class),2 靜態變量(static變量),3 靜態方法,4 常量,5 成員方法都存儲在方法區
方法區和棧區,被所有線程共享,是不安全的
在這裏插入圖片描述

  • GC機制由 JVM 提供,用來清理需要清除的對象,回收堆內存
  • GC由垃圾回收器守護線程執行
  • 從內存回收一個對象之前,會調用對象的finalize()方法
  • 開發者不能強制 JVM 執行 GC,GC的觸發機制由 JVM 依據堆內存的大小來決定;但是可以通過不同的引用類來輔助垃圾回收器工作(弱引用或軟引用)
  • System.gc() 和 Runtime.gc() 會向 JVM 發送執行 GC的請求,但是 JVM 不保證一定會執行 GC
2 總結
  • 爲了分代垃圾回收,Java堆內存分爲3代:新生代,老年代,永久代
  • 新的對象實例會優先分配在新生代,在經歷幾次 Minor GC後(默認15次),還存活的會被遷移至老年代(某些大對象會直接在老年代分配)
  • 永久代是否執行GC,取決於採用的 JVM
  • Minor GC 發生在新生代,當 Eden區沒有足夠空間時,會發起一次 Minor GC,將 Eden區中的存活對象遷移至 Survivor區,Major GC 發生在老年代,當 升到老年代的對象,大於老年代剩餘空間時,會發生 Major GC
  • 發生 Major GC時,用戶線程會暫停,會降低系統性能和吞吐量
  • JVM的參數-Xmx和-Xms用來設置Java堆內存的初始大小和最大值。依據個人經驗這個值的比例最好是1:1或者1:1.5。比如,你可以將-Xmx和-Xms都設爲1GB,或者-Xmx和-Xms設爲1.2GB和1.8GB
3 堆內存的劃分

Java中對象都在堆上創建。爲了GC,堆內存分爲三個部分,也可以說三代,分別稱爲新生代,老年代和永久代。其中新生代又進一步分爲Eden區,Survivor 1區和Survivor 2區(如下圖)。新創建的對象會分配在Eden區,在經歷一次Minor GC後會被移到Survivor 1區,再經歷一次Minor GC後會被移到Survivor 2區,直到升至老年代,需要注意的是,一些大對象(長字符串或數組)可能會直接存放到老年代
Eden與兩個Survivor的內存大小比例大概是 8:1:1
永久代有一些特殊,它用來存儲類的元信息。對於GC是否發生在永久代有許多不同的看法,在我看來這取決於採用的JVM。大家可以通過創建大量的字符串來觀察是發生了GC還是拋出了OutOfMemoryError

在這裏插入圖片描述

4 GC算法
4.1 標記清除算法

分爲標記清除兩個階段
首先標記出所有需要回收的對象,在標記完成後,統一回收所有被標記的對象
該算法的缺點是:效率不高,並且會產生不連續的碎片

在這裏插入圖片描述

4.2 複製算法

把內存空間劃爲兩個區域,每次只使用其中一個區域
垃圾回收時,遍歷當前使用區域,把正在使用中的對象複製到另外一個區域中。
算法每次只處理正在使用中的對象,因此複製成本比較小,同時複製過去後還能進行相應的內存整理,不會出現"碎片"問題
優點:實現簡單,運行高效。 缺點:會浪費一定的內存
一般新生代才用這種算法

在這裏插入圖片描述

4.3 標記整理算法

標記階段與標記清除算法一樣,但後續並不是直接對可回收的對象進行清理,而是
讓所有存活對象都向一端移動,然後清理
優點:不會造成內存碎片

在這裏插入圖片描述

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