GC(Allocation Failure)引發的一些JVM知識點梳理
https://blog.csdn.net/zc19921215/article/details/83029952
日前檢視某個程式的日誌,發現一直在報GC相關的資訊,不確定這樣的資訊是代表正確還是不正確,所以正好藉此機會再複習下GC相關的內容:
以其中一行為例來解讀下日誌資訊:
[GC (Allocation Failure) [ParNew: 367523K->1293K(410432K), 0.0023988 secs] 522739K->156516K(1322496K), 0.0025301 secs] [Times: user=0.04 sys=0.00, real=0.01 secs]
GC:
表明進行了一次垃圾回收,前面沒有Full修飾,表明這是一次Minor GC ,注意它不表示只GC新生代,並且現有的不管是新生代還是老年代都會STW。
Allocation Failure:
表明本次引起GC的原因是因為在年輕代中沒有足夠的空間能夠儲存新的資料了。
ParNew:
表明本次GC發生在年輕代並且使用的是ParNew垃圾收集器。ParNew是一個Serial收集器的多執行緒版本,會使用多個CPU和執行緒完成垃圾收集工作(預設使用的執行緒數和CPU數相同,可以使用-XX:ParallelGCThreads引數限制)。該收集器採用複製演算法回收記憶體,期間會停止其他工作執行緒,即Stop The World。
367523K->1293K(410432K):單位是KB
三個引數分別為:GC前該記憶體區域(這裡是年輕代)使用容量,GC後該記憶體區域使用容量,該記憶體區域總容量。
0.0023988 secs:
該記憶體區域GC耗時,單位是秒
522739K->156516K(1322496K):
三個引數分別為:堆區垃圾回收前的大小,堆區垃圾回收後的大小,堆區總大小。
0.0025301 secs:
該記憶體區域GC耗時,單位是秒
[Times: user=0.04 sys=0.00, real=0.01 secs]:
分別表示使用者態耗時,核心態耗時和總耗時
分析下可以得出結論:
該次GC新生代減少了367523-1293=366239K
Heap區總共減少了522739-156516=366223K
366239 – 366223 =17K,說明該次共有17K記憶體從年輕代移到了老年代,可以看出來數量並不多,說明都是生命週期短的物件,只是這種物件有很多。
我們需要的是儘量避免Full GC的發生,讓物件儘可能的在年輕代就回收掉,所以這裡可以稍微增加一點年輕代的大小,讓那17K的資料也儲存在年輕代中。
GC時,用什麼方法判斷哪些物件是需要回收:
引用計數法(已經不用了)
可達性分析法
前一種簡而言之就是給物件新增一個引用計數器,有其他地方引用時這個計數器+1,引用失效時-1,為0時就可以刪除掉了。但是它不能解決迴圈引用的問題,所以一般使用的都是後一種演算法。
可達性分析法的基本思路就是通過一系列名為GC Roots的物件作為起始點,從這些節點開始向下搜尋,搜尋所走過的路徑稱為引用鏈(Reference Chain),當一個物件到GC Roots沒有任何引用鏈相連時,則證明此物件是不可用的,那就可以回收掉了。
GC Roots一般都是些堆外指向堆內的引用,例如:
JVM棧中引用的物件
方法區中靜態屬性引用的物件
方法區中常量引用的物件
本地方法棧中引用的物件
以CMS為例,補充一些知識點介紹:
複製演算法介紹:
因為新生代物件生命週期一般很短,現在一般將該記憶體區域劃分為三塊部分,一塊大的叫Eden,兩塊小的叫Survivor。他們之間的比例一般為8:1:1。
使用的時候只使用Eden + 一塊Survivor。用Eden區用滿時會進行一次minor gc,將存活下面的物件複製到另外一塊Survivor上。如果另一塊Survivor放不下(對應虛擬機器引數為 XX:TargetSurvivorRatio,預設50,即50%),物件直接進入老年代。
(使用CMS時,預設的新生代收集器是ParNew)(有時新生代GC時,需要找到老年代中引用的新生代物件,這個時候會用到一種叫“卡表”的技術,避免老年代的全表掃描,具體怎麼操作的暫時還不知道……)
Survivor區的意義:
如果沒有survivor,Eden每進行一次minor gc,存活的物件就會進入老年代,老年代很快被填滿就會進入major gc。由於老年代空間一般很大,所以進行一次gc耗時要長的多!尤其是頻繁進行full GC,對程式的響應和連線都會有影響!
Survivor存在就是減少被送到老年代的物件,進而減少Full gc的發生。預設設定是經歷了16次minor gc還在新生代中存活的物件才會被送到老年代。
為什麼要有兩個Survivor:
主要是為了解決記憶體碎片化和效率問題。如果只有一個Survivor時,每觸發一次minor gc都會有資料從Eden放到Survivor,一直這樣迴圈下去。注意的是,Survivor區也會進行垃圾回收,這樣就會出現記憶體碎片化問題。如下圖所示:
碎片化會導致堆中可能沒有足夠大的連續空間存放一個大物件,影響程式效能。如果有兩塊Survivor就能將剩餘物件集中到其中一塊Survivor上,避免碎片問題。如下圖所示:
Minor GC和Full GC的區別以及觸發條件:
Minor gc:
對於複製演算法來說,當年輕代Eden區域滿的時候會觸發一次minor gc,將Eden和Survivor的物件複製到另外一塊Survivor上,並且某個物件存活的時間超過一定minor gc次數直接進入老年代(預設15次,對應虛擬機器引數 -XX:+MaxTenuringThreshold)。
Full gc:(又叫major gc)
用於回收老年代。當老年代空間不足或者直接呼叫System.gc(不一定有用)時,會進行一次Full gc。(HotSpot還有一些其他複雜的觸發條件,JDK8之前HotSpot的JVM中還有一個永久代(Perm區),如果永久代記憶體不足也會觸發Full gc。永久代主要存放一些class和後設資料的資訊 ---- 對應JVM規範中的方法區)
一次Full gc很有可能會由一次minor gc觸發,也可能是無法找到一塊連續的空間分配給大物件而觸發。
PS:JDK8中HotSpot為什麼要取消永久代
JDK8取消了永久代,新增了一個叫元空間(Metaspace)的區域,對應的還是JVM規範中的方法區。區別在於元空間使用的並不是JVM中的記憶體,而是使用本地記憶體。
而這麼做的原因大致有以下幾點:
1、字串存在永久代中,容易出現效能問題和記憶體溢位。
2、類及方法的資訊等比較難確定其大小,因此對於永久代的大小指定比較困難,太小容易出現永久代溢位,太大則容易導致老年代溢位。
3、永久代會為 GC 帶來不必要的複雜度,並且回收效率偏低。
4、Oracle 可能會將HotSpot 與 JRockit 合二為一。
補充下JDK8記憶體模型圖:
參考:
https://blog.csdn.net/antony9118/article/details/51425581(兩個Survivor的意義)
https://zhidao.baidu.com/question/1111800566588999699.html(Full GC什麼時候觸發)
https://blog.csdn.net/l1394049664/article/details/81486470#%E4%BA%94%E3%80%81java8%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B%E5%9B%BE(JDK8記憶體模型圖)
https://blog.csdn.net/quinnnorris/article/details/75040538(可達性分析演算法解析)
https://segmentfault.com/a/1190000007726689(卡表是什麼)
相關文章
- 【整理】JVM知識點大梳理JVM
- JVM面試知識點梳理JVM面試
- 頻繁GC (Allocation Failure)及young gc時間過長分析GCAI
- 一起來梳理JVM知識點JVM
- 《面試補習》- JVM知識點大梳理面試JVM
- 作業系統併發的一些知識點梳理作業系統
- JVM培訓之一些GC演算法的理論知識JVMGC演算法
- 關於umijs+dva+antDesign 一些知識點的梳理JS
- JVM的GC理論知識 – Bare.Metal.DevJVMGCdev
- Python基礎知識點梳理Python
- Java基礎知識點梳理Java
- JS函式知識點梳理JS函式
- Flex 佈局知識點梳理Flex
- Java併發相關知識點梳理和研究Java
- JS開發中函式知識點梳理(二)JS函式
- 圖片上傳知識點梳理
- Redux 知識點梳理和實踐Redux
- 一些cookie的知識點Cookie
- mysql的一些知識點MySql
- JVM最常見的知識點總結JVM
- AcWing 進階課知識點模板梳理
- JVM必備基礎知識(三)-- GC垃圾回收機制JVMGC
- jvm、gc、作業系統等基礎知識總結JVMGC作業系統
- web知識梳理Web
- JavaWeb知識梳理JavaWeb
- Mysql知識梳理MySql
- Python知識梳理Python
- webpack 知識梳理Web
- PLSQL一些常用的知識點SQL
- JVM相關知識點總結JVM
- JVM知識點掃盲系列(2)JVM
- 多執行緒基礎知識點梳理執行緒
- 每日一個知識點:什麼時候會觸發Full GCGC
- 關於AP的一些知識點
- vue的一些基礎知識點Vue
- react 知識梳理(一)React
- 「入門篇」初識JVM (下下) - GCJVMGC
- Linux——檔案傳輸協議知識點梳理Linux協議