1. 程式人生 > 其它 >jvm-垃圾回收器

jvm-垃圾回收器

垃圾回收的相關概念

System.gc()

預設情況下,通過system gc 的呼叫會顯示觸發Full GC,同時對新生代和老年代進行回收,嘗試釋放被丟棄物件佔用的記憶體。

記憶體溢位

javadoc 對OOM的解釋是沒有空閒記憶體,並且垃圾收集器也無法提供更多的記憶體

  • 沒有空閒記憶體說明java虛擬機器的堆記憶體不夠,比如可能存在記憶體洩漏問題,也有可能堆的大小不合理;程式碼中建立了大量的大物件,並且長時間不能被垃圾收集器收集;老版本JVM對永久代垃圾回收非常不積極,元空間的引入,出現OOM :metaspace
  • 在丟擲OOM異常之前,通常垃圾收集器會被觸發盡其所能去收集空間 ,嘗試回收軟引用指向的物件,system gc 呼叫; 當然也不是任何情況垃圾回收器都會被觸發,分配一個超級大的物件,JVM判斷垃圾收集器不能解決的這個問題,會直接丟擲OOM

記憶體洩漏

嚴格來說,只有物件不會被程式用到但是GC又不能回收他們的情況,才叫記憶體洩漏。但是實際情況一些不好的實踐也會導致物件的生命週期變得很長,甚至OOM,也可以叫做寬泛意義上的記憶體洩漏。這裡的記憶體不是指實體記憶體,而是虛擬機器記憶體大小

STW

stop the world 簡稱STW ,指的是GC事件發生過程中,會產生應用程式停頓,停頓產生的時候整個應用程式執行緒都會被暫停,沒有任何響應,STW事件和採用哪款GC無關,STW是JVM後臺自動發起和完成的,在使用者不可見的情況下,把使用者正常的工作執行緒全部停掉

安全點

程式執行時並非在所有地方都能停下來開始GC,只有在特定位置才能停下來開始GC,這些位置稱為安全點

,安全點的選擇十分重要,如果太少可能導致GC等待時間太長,太頻繁就會導致執行時的效能問題,通常會根據是否具有讓程式長時間執行的特性為標準,比如選一些執行指令(方法呼叫,迴圈跳轉,異常跳轉等)為安全點,在GC發生時,設定一箇中斷標誌,各個執行緒執行到安全點的時候主動輪詢這個標誌,為true就將自己進行的中斷掛起

在垃圾回收器的眼中只有垃圾回收執行緒(collector執行緒)以及修改物件的執行緒(Mutator執行緒),由於垃圾回收執行緒也需要修改物件,尤其在垃圾回收的過程中可能有移動物件情況,在垃圾回收時一般需要全過程或者部分過程暫停mutator執行緒,這種現象叫做STW,在hotspot 使用安全點作為制度性STw機制,安全點本質是一頁記憶體。虛擬機器將 讀取安全點記憶體頁 的操作安插在合適的地方,當程式沒有請求垃圾回收時,安全點記憶體頁可讀(good page),mutator執行緒對安全點的訪問怒會引發問題,當需要垃圾回收,VMThread將安全點設定為不可讀不可寫(bad page),然後等待所有mutator執行緒走到安全點,由於mutator執行緒訪問不可讀不可寫的記憶體會引發異常訊號,虛擬機器可以通過內部訊號處理器捕獲並停止mutator執行緒的執行,這樣相當於讓所有mutator執行緒主動停止。

安全區域

指一段程式碼片段,物件的引用關係不會發生變化,這個區域的任何位置開始GC都是安全的。

safepointSynchronize begin ,safepointSynchronize end 分別表示安全點的開啟和關閉,兩者之間構成了一個安全區域。VMThread會等待所有執行緒,直到都達到安全點,此時安全點開啟成功,開啟安全點的核心是執行緒狀態的轉換,不同執行緒進入安全點的方式也不同。

垃圾回收器概述

垃圾回收器可以由不同廠商、不同版本的JVM實現,從不同的角度可以將GC分為不同

  1. 吞吐量 :CPU執行使用者程式碼的時間與CPU總消耗時間的比值
  2. 暫停時間:執行垃圾收集時,程式的工作執行緒被暫停的時間
  3. 記憶體佔用:java堆區所佔用的記憶體大小

Serial 回收器:序列回收

Serial回收器是最基本歷史最悠久的垃圾收集器,serial(serial old)作為hotspot中client模式下的預設新生代(老年代)垃圾收集器,是單執行緒收集器,在進行垃圾收集時必須暫停其他所有的工作執行緒,直到收集結束。新生代採用複製演算法,老年代採用標記整理演算法。

Parallel 回收器:吞吐量優先

新生代採用複製演算法,老年代採用標記整理演算法。

CMS 回收器:低延遲(併發收集)

第一款真正意義上的併發收集器,第一次實現了讓垃圾收集執行緒和使用者執行緒同時工作。整個過程分為4個主要階段

  • 初始標記:程式中所有工作執行緒都會因為STW機制出現短暫的暫停,這個階段主要任務是標記出GC roots能直接關聯的物件,一旦標記完後就會互動之前被暫停的所有應用執行緒。
  • 併發標記:從GC root的直接關聯物件開始遍歷整個物件圖的過程,這個過程耗時但是不需要停頓使用者執行緒,可以與垃圾收集執行緒要一起併發執行。
  • 重新標記:為了修正併發標記期間,因使用者程式繼續運作而導致標記產生變動的那一部分物件的標記記錄,這個階段的停頓時間通常會比初始階段稍微長一些,並且會導致STW,但也遠比並發標記階段短
  • 併發清除:清理刪除掉標記階段判斷的已經死亡的物件,釋放記憶體空間,由於不需要移動存活物件,所以這個階段可以與使用者執行緒同時併發

注意在垃圾收集階段使用者執行緒並沒有中斷,所以在CMS回收過程中,應該確保使用者執行緒有足夠的記憶體可用,當堆記憶體使用率達到某一閾值便開始回收,CMS垃圾收集演算法採用的標記清除演算法,不可避免的產生一些記憶體碎片,在為新物件分配記憶體空間時候只能選擇空閒列表執行記憶體分配。

G1 回收器:區域化分代式