JVM 调优实战--常见的垃圾回收算法及垃圾收集器组合
什么是垃圾
C語言申請內存:malloc free
C++: new delete
c/C++ 手動回收內存
Java: new ?
自動內存回收,編程上簡單,系統不容易出錯,手動釋放內存,容易出兩種類型的問題:
忘記回收
多次回收
沒有任何引用指向的一個對象或者多個對象(循環引用)
如何定位垃圾
①引用計數法
②跟可達算法
常見的垃圾回收算法
標記清除 - 位置不連續 產生碎片 效率偏低(兩遍掃描)
拷貝算法 - 沒有碎片,浪費空間
標記壓縮 - 沒有碎片,效率偏低(兩遍掃描,指針需要調整)
JVM內存分代模型
jdk1.7永久代存放的是各種Class文件,如使用Spring等框架會產生大量代理對象,它們的Class對象就存放在永久代中。
字符串常量:1.7是存放在永久代方法區MethodArea中,1.8存放在堆中。
MethodArea方法區:
①1.7叫做Perm Generation,1.8叫做Metaspace元數據區。
②里面存放的是class的元信息,代碼的編譯信息,各種層次信息,JIT編譯信息(JNI)等凡是跟JVM自身的class無關的其他信息都存放在方法區這個邏輯分區里面。
③在1.7版本,必須指定固定大小,而且很容易溢出。1.8之后內存的大小設置受限于物理內存,既可以設置也可以不設置,不設置理論上在物理內存范圍內無上限。
堆內存:包括年輕代和老年代
堆外內存:包括永久代和元數據區(曾用名:方法區)
部分垃圾回收器使用的模型
除Epsilon ZGC Shenandoah之外的GC都是使用邏輯分代模型
G1是邏輯分代,物理不分代
除此之外不僅邏輯分代,而且物理分代
新生代 + 老年代 + 永久代(1.7)/ 元數據區(1.8) Metaspace
永久代 元數據 - Class
永久代必須指定大小限制 ,元數據可以設置,也可以不設置,無上限(受限于物理內存)
字符串常量 1.7 - 永久代,1.8 - 堆
MethodArea邏輯概念 - 永久代、元數據
新生代 = Eden + 2個suvivor區
YGC回收之后,大多數的對象會被回收,活著的進入s0
再次YGC,活著的對象eden + s0 -> s1
再次YGC,eden + s1 -> s0
年齡足夠 -> 老年代 (15 CMS 6)
s區裝不下 -> 老年代
老年代
頑固分子
老年代滿了FGC Full GC
GC Tuning (Generation)
盡量減少FGC
MinorGC = YGC
MajorGC = FGC
對象分配過程圖
7.動態年齡:(不重要) https://www.jianshu.com/p/989d3b06a49d
8.分配擔保:(不重要) YGC期間 survivor區空間不夠了 空間擔保直接進入老年代
對象的分配過程:
先在棧上跑,也就是棧上分配,看大不大,如果比較大的話就進入Old區,如果不是很大,就先進行線程本地分配,?都進入Eden區,如果能清除就清除,不能清除就進入S1,S1再來一遍,看年齡滿了沒有,年齡夠了就進Old區,如果不夠就進入S2,就這樣循環往復。
常見的垃圾收集器
常見的使用組合是:
①Serial+Serial Old
②ParNew+CMS
③Parallel Scavenge+Parallel Old (PS+PO jdk1.8默認的)
④G1
這些使用組合沒有孰優孰劣,得分不同的場景來選擇。比方說,老的機器上可能使用單線程的Serial更合適。
ParNew+CMS是高響應,低停頓,但吞吐量降低。
JDK誕生 Serial追隨 提高效率,誕生了PS,為了配合CMS,誕生了PN,CMS是1.4版本后期引入,CMS是里程碑式的GC,它開啟了并發回收的過程,但是CMS毛病較多,因此目前任何一個JDK版本默認是CMS 并發垃圾回收是因為無法忍受STW
Serial 年輕代 串行回收
PS 年輕代 并行回收
ParNew 年輕代 配合CMS的并行回收
SerialOld
ParallelOld
ConcurrentMarkSweep 老年代 并發的, 垃圾回收和應用程序同時運行,降低STW的時間(200ms) CMS問題比較多,所以現在沒有一個版本默認是CMS,只能手工指定 CMS既然是MarkSweep,就一定會有碎片化的問題,碎片到達一定程度,CMS的老年代分配對象分配不下的時候,使用SerialOld 進行老年代回收 想象一下: PS + PO -> 加內存 換垃圾回收器 -> PN + CMS + SerialOld(幾個小時 - 幾天的STW) 幾十個G的內存,單線程回收 -> G1 + FGC 幾十個G -> 上T內存的服務器 ZGC 算法:三色標記 + Incremental Update
G1(10ms) 算法:三色標記 + SATB
ZGC (1ms) PK C++ 算法:ColoredPointers + 寫屏障?
Shenandoah 算法:ColoredPointers + 讀屏障?
Eplison
PS 和 PN區別的延伸閱讀: ?https://docs.oracle.com/en/java/javase/13/gctuning/ergonomics.html#GUID-3D0BB91E-9BFF-4EBB-B523-14493A860E73
垃圾收集器跟內存大小的關系
Serial 幾十兆
PS 上百兆 - 幾個G
CMS - 20G
G1 - 上百G
ZGC - 4T
1.8默認的垃圾回收:PS + ParallelOld
常見垃圾回收器組合參數設定:(1.8)
-
-XX:+UseSerialGC = Serial New (DefNew) + Serial Old
-
小型程序。默認情況下不會是這種選項,HotSpot會根據計算及配置和JDK版本自動選擇收集器
-
-
-XX:+UseParNewGC = ParNew + SerialOld
-
這個組合已經很少用(在某些版本中已經廢棄)
-
https://stackoverflow.com/questions/34962257/why-remove-support-for-parnewserialold-anddefnewcms-in-the-future
-
-
-XX:+UseConc(urrent)MarkSweepGC = ParNew + CMS + Serial Old(jdk1.8的命令是UseConcMarkSweepGC,有的jdk版本是要加上紅色字體部分的。Serial Old是替補)
-
-XX:+UseParallelGC = Parallel Scavenge + Parallel Old (1.8默認) 【PS + SerialOld】
-
-XX:+UseParallelOldGC = Parallel Scavenge + Parallel Old
-
-XX:+UseG1GC = G1
-
Linux中沒找到默認GC的查看方法,而windows中會打印UseParallelGC
-
java +XX:+PrintCommandLineFlags -version
-
通過GC的日志來分辨
-
-
Linux下1.8版本默認的垃圾回收器到底是什么?
-
1.8.0_181 默認(看不出來)Copy MarkCompact
-
1.8.0_222 默認 PS + PO
-
?
怎么調優
所謂調優,首先要確定追求的是啥?是吞吐量優先還是響應時間優先?或者是在滿足一定的響應時間的前提下,要求達到一定的吞吐量?有的放矢才能做好調優這活!
如果是選擇吞吐量優先,一般選擇的是PS+PO這個組合
如果是響應時間優先,比如網站,GUI,API服務等,1.8版本選擇G1垃圾收集器。
?
?
jconsole遠程連接
程序啟動加入參數:
java -Djava.rmi.server.hostname=192.168.17.11 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=11111 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false XXX如果遭遇 Local host name unknown:XXX的錯誤,修改/etc/hosts文件,把XXX加入進去
192.168.17.11 basic localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 ? ? ? ? localhost localhost.localdomain localhost6 localhost6.localdomain6關閉linux防火墻(實戰中應該打開對應端口)
service iptables stop chkconfig iptables off #永久關閉windows上打開 jconsole遠程連接 192.168.17.11:11111
?
jprofiler (收費)
arthas在線排查工具
為什么需要在線排查? 在生產上我們經常會碰到一些不好排查的問題,例如線程安全問題,用最簡單的threaddump或者heapdump不好查到問題原因。為了排查這些問題,有時我們會臨時加一些日志,比如在一些關鍵的函數里打印出入參,然后重新打包發布,如果打了日志還是沒找到問題,繼續加日志,重新打包發布。對于上線流程復雜而且審核比較嚴的公司,從改代碼到上線需要層層的流轉,會大大影響問題排查的進度。
CMS
CMS的問題
Memory Fragmentation
-XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction 默認為0 指的是經過多少次FGC才進行壓縮
Floating Garbage
Concurrent Mode Failure 產生:if the concurrent collector is unable to finish reclaiming the unreachable objects before the tenured generation fills up, or if an allocation cannot be satisfiedwith the available free space blocks in the tenured generation, then theapplication is paused and the collection is completed with all the applicationthreads stopped
解決方案:降低觸發CMS的閾值
PromotionFailed
解決方案類似,保持老年代有足夠的空間
–XX:CMSInitiatingOccupancyFraction 92% 可以降低這個值,讓CMS保持老年代足夠的空間
總結
以上是生活随笔為你收集整理的JVM 调优实战--常见的垃圾回收算法及垃圾收集器组合的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: RabbitMQ使用${}读取配置文件中
- 下一篇: MyCat实战--读写分离/数据分片/m