【JVM调优】JVM内存管理调优浅谈
什么是JVM
Java Virtual Machine,Java虛擬機(jī)
Java虛擬機(jī)有自己完善的硬件架構(gòu),如處理器、堆棧等,還具有相應(yīng)的指令系統(tǒng)。
Java虛擬機(jī)本質(zhì)上就是一個(gè)程序,當(dāng)它在命令行上啟動(dòng)的時(shí)候,就開始執(zhí)行保存在某字節(jié)碼文件中的指令。Java語言的可移植性正是建立在Java虛擬機(jī)的基礎(chǔ)上。任何平臺(tái)只要裝有針對(duì)于該平臺(tái)的Java虛擬機(jī),字節(jié)碼文件(.class)就可以在該平臺(tái)上運(yùn)行。這就是“一次編譯,多次運(yùn)行”。
Java虛擬機(jī)不僅是一種跨平臺(tái)的軟件,而且是一種新的網(wǎng)絡(luò)計(jì)算平臺(tái)。該平臺(tái)包括許多相關(guān)的技術(shù),如符合開放接口標(biāo)準(zhǔn)的各種API、優(yōu)化技術(shù)等。Java技術(shù)使同一種應(yīng)用可以運(yùn)行在不同的平臺(tái)上。Java平臺(tái)可分為兩部分,即Java虛擬機(jī)(Java virtual machine,JVM)和Java API類庫(kù)。
作用:JVM是java字節(jié)碼執(zhí)行的引擎,解析字節(jié)碼文件的內(nèi)容,并將其翻譯為各種操作系統(tǒng)能理解的機(jī)器碼
運(yùn)作過程:解析字節(jié)碼文件的時(shí)候,會(huì)先加載字節(jié)碼文件,將其存入java虛擬機(jī)的內(nèi)存空間中,進(jìn)行一系列的動(dòng)作,最后運(yùn)行程序得出結(jié)果
JVM內(nèi)存空間
字節(jié)碼數(shù)據(jù)在java虛擬機(jī)內(nèi)存中如何存放的?
虛擬機(jī)棧
用于執(zhí)行java方法,每個(gè)方法執(zhí)行都會(huì)創(chuàng)建一個(gè)棧幀,存儲(chǔ)局部變量表,操作數(shù)棧,動(dòng)態(tài)鏈接等信息,程序執(zhí)行時(shí),棧幀入棧,執(zhí)行完成后棧幀出棧
程序計(jì)數(shù)器
或者叫PC寄存器,記載著每一個(gè)線程當(dāng)前運(yùn)行的JAVA方法的地址,指示當(dāng)前程序執(zhí)行到了哪個(gè)位置:
1、執(zhí)行Java方法時(shí)記錄正在執(zhí)行的虛擬機(jī)字節(jié)碼指令地址;
2、執(zhí)行本地方法時(shí),計(jì)數(shù)器值為null;
每一個(gè)線程都有一個(gè)PC寄存器,也就是說PC寄存器是線程獨(dú)有的。
生命周期跟隨線程,線程啟動(dòng)而產(chǎn)生,線程結(jié)束而消亡。
是一塊較小的內(nèi)存空間,它的作用可以看做是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器。
本地方法區(qū)
如果程序有使用到native方法,加載和執(zhí)行就在這個(gè)區(qū)域。
方法區(qū)
存儲(chǔ) Java 類字節(jié)碼數(shù)據(jù)的一塊區(qū)域,存儲(chǔ)類,常量相關(guān)的信息。
Java堆
Java虛擬機(jī)管理的內(nèi)存中最大的一塊,Java虛擬機(jī)啟動(dòng)的時(shí)候建立,所有線程共享,幾乎所有的對(duì)象實(shí)例都在這里分配內(nèi)存。
GC主要就是在Java堆中進(jìn)行的。
Java 堆根據(jù)對(duì)象存活時(shí)間的不同,Java 堆還被分為新生代(或叫 年輕代)、老年代兩個(gè)區(qū)域,新生代還被進(jìn)一步劃分為 Eden 區(qū)、Survivor 0、Survivor 1 區(qū)。
新生代
老年代
GC介紹
GC,即垃圾回收
英語:Garbage Collection,縮寫為GC
GC是一種自動(dòng)的內(nèi)存管理機(jī)制
垃圾回收的術(shù)語:
Minor GC
從新生代空間回收內(nèi)存被稱為 Minor GC,有時(shí)候也稱之為 Young GC。
Major GC
從老年代空間回收內(nèi)存被稱為 Major GC,有時(shí)候也稱之為 Old GC。
Full GC
Full GC 是清理整個(gè)堆空間 —— 包括新生代、老年代。因此 Full GC 可以說是 Minor GC 和 Major GC 的結(jié)合。
Stop-The-World
翻譯為全世界暫停,簡(jiǎn)稱 STW,是指在進(jìn)行垃圾回收時(shí),因?yàn)闃?biāo)記或清理的需要,必須讓所有執(zhí)行任務(wù)的線程停止執(zhí)行任務(wù),從而讓垃圾回收線程完成回收垃圾的時(shí)間。
垃圾回收機(jī)制的重點(diǎn):
哪些內(nèi)存需要回收?
垃圾收集器會(huì)對(duì)堆進(jìn)行回收前,確定對(duì)象中哪些是“存活”,哪些是“死亡”(不可能再被任何途徑使用的對(duì)象);
當(dāng)一個(gè)對(duì)象到GC Roots沒有任何引用鏈相連,即不可達(dá)時(shí),則證明此對(duì)象時(shí)不可用的。
舉例:一顆樹有很多丫枝,其中一個(gè)分支斷了,跟樹上沒有任何聯(lián)系,那就說明這個(gè)分支沒有用了,就可以當(dāng)垃圾回收去燒了。
什么時(shí)候回收?
主要的場(chǎng)景:
(1)JVM 無法為一個(gè)新的對(duì)象分配空間時(shí)會(huì)觸發(fā) Minor GC
(2)老年代空間不夠,那么觸發(fā) Major GC
(3)當(dāng)準(zhǔn)備要觸發(fā)一次Minor GC時(shí),如果出現(xiàn)歷史Minor GC的平均晉升大小比目前 “老年代”剩余的空間大,老年代剩余空間不夠用于新生代晉升,則不會(huì)觸發(fā)young GC,而是轉(zhuǎn)為觸發(fā)full GC
如何回收?
垃圾收集算法:
1)標(biāo)記—清除算法
標(biāo)記—清除算法(Mark-Sweep),是最基礎(chǔ)的收集算法,它分為“標(biāo)記”和“清除”兩個(gè)階段:首先標(biāo)記出所需回收的對(duì)象,在標(biāo)記完成后統(tǒng)一回收掉所有被標(biāo)記的對(duì)象,它的標(biāo)記過程是通過可達(dá)性分析算法實(shí)現(xiàn)的。
回收前狀態(tài)
回收后狀態(tài)
算法缺點(diǎn):
標(biāo)記和清除過程的效率都不高;標(biāo)記清除后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片。
2)復(fù)制算法
復(fù)制算法將可用內(nèi)存按容量分為大小相等的兩塊,每次只使用其中的一塊,當(dāng)這一塊的內(nèi)存用完了,就將還存活著的對(duì)象復(fù)制到另外一塊內(nèi)存上面,然后再把已使用過的內(nèi)存空間一次清理掉。
回收前狀態(tài)
回收后狀態(tài)
復(fù)制算法優(yōu)點(diǎn):
每次只對(duì)一塊內(nèi)存進(jìn)行回收,運(yùn)行高效;大大減少了內(nèi)存碎片的出現(xiàn);
缺點(diǎn):
可初始分配的最大內(nèi)存縮小了一半;
3)標(biāo)記—整理算法
分為“標(biāo)記”、“整理”、“清除”三個(gè)階段
先對(duì)內(nèi)存區(qū)域的對(duì)象進(jìn)行標(biāo)記,區(qū)分出“存活對(duì)象”和“可回收對(duì)象”,
讓所有的對(duì)象都向內(nèi)存區(qū)域一端移動(dòng),直接清理掉可回收的對(duì)象;
回收前狀態(tài)
回收后狀態(tài)
4)分代回收
根據(jù)對(duì)象的存活周期的不同,將內(nèi)存劃分為新生代和老年代。
在新生代中,每次垃圾收集時(shí)都會(huì)發(fā)現(xiàn)有大量對(duì)象死去,只有少量存活,因此可選用復(fù)制算法來完成收集;
新生代中的對(duì)象98%都是“朝生夕死”的,所以并不需要按照1:1的比例來劃分內(nèi)存空間,而是將內(nèi)存分為一塊比較大的Eden空間和兩塊較小的Survivor空間(8:1:1的比例),每次使用Eden和其中一塊Survivor。當(dāng)回收時(shí),將Eden和Survivor中還存活著的對(duì)象一次性地復(fù)制到另外一塊Survivor空間上,最后清理掉Eden和剛才用過的Survivor空間。
每次新生代中可用內(nèi)存空間為整個(gè)新生代容量的90%(80%+10%),只有10%的空間會(huì)被預(yù)留。
老年代中因?yàn)閷?duì)象存活率高、沒有額外空間對(duì)它進(jìn)行分配擔(dān)保,就使用標(biāo)記—清除算法或標(biāo)記—整理算法來進(jìn)行回收
新生代回收
JVM常用參數(shù)
Jvm啟動(dòng)參數(shù)共分為三類:
一、是標(biāo)準(zhǔn)參數(shù)(-),所有的JVM實(shí)現(xiàn)都必須實(shí)現(xiàn)這些參數(shù)的功能,而且向后兼容;
二、是非標(biāo)準(zhǔn)參數(shù)(-X),默認(rèn)jvm實(shí)現(xiàn)這些參數(shù)的功能,但是并不保證所有jvm實(shí)現(xiàn)都滿足,且不保證向后兼容;
三、是非Stable參數(shù)(-XX),此類參數(shù)各個(gè)jvm實(shí)現(xiàn)會(huì)有所不同;
-Xms256m 為jvm啟動(dòng)時(shí)分配的內(nèi)存-Xmx256m 為jvm運(yùn)行過程中分配的最大內(nèi)存,建議和Xms保持一致-Xmn128m 設(shè)置年輕代大小為128M 此值對(duì)系統(tǒng)性能影響較大,Sun官方推薦配置為整個(gè)堆的3/8。-Xss256k 為jvm啟動(dòng)的每個(gè)線程分配的內(nèi)存大小-XX:NewSize 和-XX:MaxNewSize 用于設(shè)置年輕代的大小,建議設(shè)為整個(gè)堆大小的1/3或者1/4,兩個(gè)值設(shè)為一樣大。-XX:PermSize=1024M 和 -XX:MaxPermSize=1024M JVM初始分配的非堆內(nèi)存, 不會(huì)被回收, 建議與maxPermSize相同-XX:SurvivorRatio=4 年輕代中Eden區(qū)與兩個(gè)Survivor區(qū)的比值。注意Survivor區(qū)有兩個(gè)。 設(shè)置為4,則兩個(gè)Survivor區(qū)與一個(gè)Eden區(qū)的比值為2:4,一個(gè)Survivor區(qū)占整個(gè)年輕代的1/6-XX:NewRatio=4 設(shè)置年輕代(EC+S0C+S1C)和年老代(OC)的比值。如:為4,表示年輕代與年老代比值為1:4,年輕代占整個(gè)年輕代年老代和的1/5-XX:InitialTenuringThreshol 和-XX:MaxTenuringThreshold 用于設(shè)置晉升到老年代的對(duì)象年齡的最小值和最大值,每個(gè)對(duì)象在堅(jiān)持過一次Minor GC之后,年齡就加1。-XX:+PrintGC 輸出GC日志 -XX:+PrintGCDetails 輸出GC的詳細(xì)日志 -XX:+PrintGCTimeStamps 輸出GC的時(shí)間戳(以基準(zhǔn)時(shí)間的形式) -XX:+PrintGCDateStamps 輸出GC的時(shí)間戳(以日期的形式,如 2013-05-04T21:53:59.234+0800) -Xloggc:../logs/gc.log 日志文件的輸出路徑-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=5 -XX:GCLogFileSize=20M JVM的一個(gè)日志文件達(dá)到了20M以后,就會(huì)寫入另一個(gè)新的文件,最多會(huì)有5個(gè)日志文件,他們的名字分別是:gc.log.0、gc.log.1 等 -XX:+PrintHeapAtGC 在進(jìn)行GC的前后打印出堆的信息-XX:+PrintTenuringDistribution 這個(gè)參數(shù)用于顯示每次Minor GC時(shí)Survivor區(qū)中各個(gè)年齡段的對(duì)象的大小。2020-06-29T03:45:25.512+0800: 76.642: [GC pause (G1 Evacuation Pause) (young) Desired survivor size 402653184 bytes, new threshold 2 (max 15) - age 1: 169351248 bytes, 169351248 total - age 2: 331023392 bytes, 500374640 total - age 3: 64201192 bytes, 564575832 total , 1.2957512 secs]-XX:MaxTenuringThreshold 用于調(diào)整對(duì)象晉升老年代的所需經(jīng)歷的GC次數(shù),默認(rèn)15次,即在年輕代的對(duì)象經(jīng)過了指定次數(shù)的 GC 后,將在下次 GC 時(shí)進(jìn)入老年代。JVM調(diào)優(yōu)淺談
JVM內(nèi)存管理很差會(huì)出現(xiàn)什么情況?
1,內(nèi)存溢出
2,頻繁Full GC
….
內(nèi)存溢出:
OutOfMemoryError: Java heap space 堆溢出
最常見的內(nèi)存溢出,當(dāng)在JVM中如果98%的時(shí)間是用于GC且可用的 Heap size 不足2%的時(shí)候?qū)伋龃水惓P畔ⅰ?/p>
優(yōu)化建議:
Heap Size 最大不要超過可用物理內(nèi)存的80%,一般的要將-Xms和-Xmx選項(xiàng)設(shè)置為相同,而-Xmn為3/8的-Xmx值。
OutOfMemoryError: PermGen space 非堆溢出(永久保存區(qū)域溢出)
這塊內(nèi)存主要是被JVM存放Class和Meta信息的,是 JVM初始分配的非堆內(nèi)存,沒有GC回收,一般發(fā)生在程序的啟動(dòng)階段。
優(yōu)化建議:
通過-XX:PermSize和 -XX:MaxPermSize設(shè)置合適的內(nèi)存大小
OutOfMemoryError: unable to create new native thread. 無法創(chuàng)建新的線程
常見在高并發(fā)的業(yè)務(wù)場(chǎng)景,線程池一直新建線程,每個(gè)線程都有自己的Stack Space,Stack Space的空間是獨(dú)立分配的,當(dāng)超出jvm的棧內(nèi)存大小時(shí), 就會(huì)報(bào)出無法再創(chuàng)建線程的錯(cuò)誤.
優(yōu)化建議:
設(shè)置合適的-Xss參數(shù),優(yōu)化線程池資源分配。
java.lang.StackOverflowError : Thread Stack space
棧溢出了,常見于代碼遞歸的層次過多。
優(yōu)化建議:
修改程序、設(shè)置合適的-Xss參數(shù)。
MinorGC 日志
2020-06-23T04:35:59.604+0800: 463.092: [GC (Allocation Failure) 2020-06-23T04:35:59.604+0800: 463.092: [ParNew: 43296K->7006K(47808K), 0.0136826 secs] 44992K->8702K(252608K), 0.0137904 secs] [Times: user=0.03 sys=0.00, real=0.02 secs] 2020-06-23T04:35:59.604+0800 日志文件的時(shí)間戳463.092 JVM記錄的時(shí)間戳:GC開始,相對(duì)JVM啟動(dòng)的相對(duì)時(shí)間,單位是秒GC 觸發(fā)了YoungGC/MinorGCAllocation Failure – MinorGC的原因,由于年輕代不滿足申請(qǐng)的空間,因此觸發(fā)了MinorGC[ParNew(使用ParNew作為新生代的垃圾回收器,采用的是復(fù)制算法): 43296K(年輕代垃圾回收前的大小)->7006K(年輕代垃圾回收以后的大小)(47808K) (年輕代的總大小), 0.0136826 secs(回收時(shí)間)] 44992K(堆區(qū)垃圾回收前的大小)->8702K(堆區(qū)垃圾回收后的大小)(252608K)(堆區(qū)總大小), 0.0137904 secs(回收時(shí)間)][Times: user=0.03 sys=0.00, real=0.02 secs] user:GC 線程在垃圾收集期間所使用的 CPU 總時(shí)間; sys:系統(tǒng)調(diào)用或者等待系統(tǒng)事件花費(fèi)的時(shí)間; real:應(yīng)用被暫停的時(shí)鐘時(shí)間,由于 GC 線程是多線程的,導(dǎo)致了 real 小于 (user+real),如果是 gc 線程是單線程的話,real 是接近于 (user+real) 時(shí)間。FullGC 日志
2018-04-12T13:48:26.233+0800: 15578.148: [GC [1 CMS-initial-mark: 6294851K(20971520K)] 6354687K(24746432K), 0.0466580 secs] [Times: user=0.04 sys=0.00, real=0.04 secs] 2018-04-12T13:48:26.280+0800: 15578.195: [CMS-concurrent-mark-start] 2018-04-12T13:48:26.418+0800: 15578.333: [CMS-concurrent-mark: 0.138/0.138 secs] [Times: user=1.01 sys=0.21, real=0.14 secs] 2018-04-12T13:48:26.418+0800: 15578.334: [CMS-concurrent-preclean-start] 2018-04-12T13:48:26.476+0800: 15578.391: [CMS-concurrent-preclean: 0.056/0.057 secs] [Times: user=0.20 sys=0.12, real=0.06 secs] 2018-04-12T13:48:26.476+0800: 15578.391: [CMS-concurrent-abortable-preclean-start] 2018-04-12T13:48:29.989+0800: 15581.905: [CMS-concurrent-abortable-preclean: 3.506/3.514 secs] [Times: user=11.93 sys=6.77, real=3.51 secs] 2018-04-12T13:48:29.991+0800: 15581.906: [GC[YG occupancy: 1805641 K (3774912 K)] 2018-04-12T13:48:29.991+0800: 15581.906: [GC2018-04-12T13:48:29.991+0800: 15581.906: [ParNew: 1805641K->48395K(3774912K), 0.0826620 secs] 8100493K->6348225K(24746432K), 0.0829480 secs] [Times: user=0.81 sys=0.00, real=0.09 secs]2018-04-12T13:48:30.074+0800: 15581.989: [Rescan (parallel) , 0.0429390 secs]2018-04-12T13:48:30.117+0800: 15582.032: [weak refs processing, 0.0027800 secs]2018-04-12T13:48:30.119+0800: 15582.035: [class unloading, 0.0033120 secs]2018-04-12T13:48:30.123+0800: 15582.038: [scrub symbol table, 0.0016780 secs]2018-04-12T13:48:30.124+0800: 15582.040: [scrub string table, 0.0004780 secs] [1 CMS-remark: 6299829K(20971520K)] 6348225K(24746432K), 0.1365130 secs] [Times: user=1.24 sys=0.00, real=0.14 secs] 2018-04-12T13:48:30.128+0800: 15582.043: [CMS-concurrent-sweep-start] 2018-04-12T13:48:38.412+0800: 15590.327: [CMS-concurrent-sweep: 8.193/8.284 secs] [Times: user=30.34 sys=16.44, real=8.28 secs] 2018-04-12T13:48:38.419+0800: 15590.334: [CMS-concurrent-reset-start] 2018-04-12T13:48:38.462+0800: 15590.377: [CMS-concurrent-reset: 0.044/0.044 secs] [Times: user=0.15 sys=0.10, real=0.04 secs]階段1:Initial Mark
2018-04-12T13:48:26.233+0800: 15578.148: [GC [1 CMS-initial-mark: 6294851K(20971520K)] 6354687K(24746432K), 0.0466580 secs] [Times: user=0.04 sys=0.00, real=0.04 secs]CMS-initial-mark:初始標(biāo)記階段,CMS是老年代垃圾回收器,基于標(biāo)記-清除算法實(shí)現(xiàn), 它會(huì)收集所有 GC Roots 以及其直接引用的對(duì)象; 6294851K:當(dāng)前老年代使用的容量,這里是 6G; (20971520K):老年代可用的最大容量,這里是 20G; 6354687K:整個(gè)堆目前使用的容量,這里是 6.06G; (24746432K):堆可用的容量,這里是 23.6G; 0.0466580 secs:這個(gè)階段的持續(xù)時(shí)間;這個(gè)是 CMS 兩次 stop-the-wolrd 事件的其中一次,這個(gè)階段的目標(biāo)是:標(biāo)記那些直接被 GC root 引用 或者被年輕代存活對(duì)象所引用的所有對(duì)象階段2:CMS-concurrent-mark
2018-04-12T13:48:26.280+0800: 15578.195: [CMS-concurrent-mark-start] 2018-04-12T13:48:26.418+0800: 15578.333: [CMS-concurrent-mark: 0.138/0.138 secs] [Times: user=1.01 sys=0.21, real=0.14 secs]CMS-concurrent-mark:并發(fā)標(biāo)記階段,遍歷老年代,標(biāo)記所有存活的對(duì)象,由第一階段標(biāo)記過的對(duì)象出發(fā), 所有可達(dá)的對(duì)象都在本階段標(biāo)記; 0.138/0.138 secs:這個(gè)階段的持續(xù)時(shí)間與時(shí)鐘時(shí)間;2018-04-12T13:48:26.418+0800: 15578.334: [CMS-concurrent-preclean-start] 2018-04-12T13:48:26.476+0800: 15578.391: [CMS-concurrent-preclean: 0.056/0.057 secs] [Times: user=0.20 sys=0.12, real=0.06 secs]階段3:Concurrent Preclean
Concurrent Preclean :并發(fā)預(yù)清理階段,對(duì)在前面并發(fā)標(biāo)記階段中引用發(fā)生變化的對(duì)象進(jìn)行標(biāo)記, 包含:從新生代晉升、新分配、被更新的對(duì)象,并發(fā)地重新掃描這些對(duì)象; 0.056/0.057 secs:這個(gè)階段的持續(xù)時(shí)間與時(shí)鐘時(shí)間;2018-04-12T13:48:26.476+0800: 15578.391: [CMS-concurrent-abortable-preclean-start] 2018-04-12T13:48:29.989+0800: 15581.905: [CMS-concurrent-abortable-preclean: 3.506/3.514 secs] [Times: user=11.93 sys=6.77, real=3.51 secs]階段4:Concurrent Abortable Preclean
Concurrent Abortable Preclean :并發(fā)可中止的預(yù)清理階段,和上一階段工作內(nèi)容一樣,但可以控制結(jié)束 時(shí)間,這個(gè)階段持續(xù)時(shí)間依賴于很多的因素:完成的工作量、掃描持續(xù)時(shí)間等;2018-04-12T13:48:29.991+0800: 15581.906: [GC[YG occupancy: 1805641 K (3774912 K)] 2018-04-12T13:48:29.991+0800: 15581.906: [GC2018-04-12T13:48:29.991+0800: 15581.906: [ParNew: 1805641K->48395K(3774912K), 0.0826620 secs] 8100493K->6348225K(24746432K), 0.0829480 secs] [Times: user=0.81 sys=0.00, real=0.09 secs] 2018-04-12T13:48:30.074+0800: 15581.989: [Rescan (parallel) , 0.0429390 secs] 2018-04-12T13:48:30.117+0800: 15582.032: [weak refs processing, 0.0027800 secs] 2018-04-12T13:48:30.119+0800: 15582.035: [class unloading, 0.0033120 secs] 2018-04-12T13:48:30.123+0800: 15582.038: [scrub symbol table, 0.0016780 secs] 2018-04-12T13:48:30.124+0800: 15582.040: [scrub string table, 0.0004780 secs] [1 CMS-remark: 6299829K(20971520K)] 6348225K(24746432K), 0.1365130 secs] [Times: user=1.24 sys=0.00, real=0.14 secs]階段5:remark
remark 重標(biāo)記階段重標(biāo)記階段(CMS的第二個(gè)STW階段),暫停所有用戶線程,從GC Root開始重新掃描整堆,標(biāo)記存活的對(duì)象。 雖然CMS只回收老年代的垃圾對(duì)象,但是這個(gè)階段依然需要掃描新生代,因?yàn)楹芏郍C Root都在新生代, 而這些GC Root指向的對(duì)象又在老年代,這稱為“跨代引用”。YG occupancy: 1805641 K (3774912 K):年輕代當(dāng)前占用量及總?cè)萘?#xff0c;這里分別是 1.71G 和 3.6G; ParNew:觸發(fā)了一次 young GC,原因是為了減少年輕代的存活對(duì)象,盡量使年輕代更干凈一些; [Rescan (parallel) , 0.0429390 secs]:這個(gè) Rescan 是當(dāng)應(yīng)用暫停的情況下完成對(duì)所有存活對(duì)象的標(biāo)記, 這個(gè)階段是并行處理的,這里花費(fèi)了 0.0429390s; [weak refs processing, 0.0027800 secs]:第一個(gè)子階段,它的工作是處理弱引用; [class unloading, 0.0033120 secs]:第二個(gè)子階段,它的工作是:unloading the unused classes; [scrub symbol table, 0.0016780 secs]、[scrub string table, 0.0004780 secs]: 最后一個(gè)子階段,它的目的是:cleaning up symbol and string tables which hold class-level metadata and internalized string respectively CMS-remark:remark結(jié)束,輸出當(dāng)前老年代的使用量與總量6299829K(20971520K), 堆的使用量與總量6348225K(24746432K)2018-04-12T13:48:30.128+0800: 15582.043: [CMS-concurrent-sweep-start] 2018-04-12T13:48:38.412+0800: 15590.327: [CMS-concurrent-sweep: 8.193/8.284 secs] [Times: user=30.34 sys=16.44, real=8.28 secs]階段6:并發(fā)清理階段
這個(gè)階段主要是清除那些沒有被標(biāo)記的對(duì)象,回收它們的占用空間;這里不需要 STW, 它是與用戶的應(yīng)用程序并發(fā)運(yùn)行。2018-04-12T13:48:38.419+0800: 15590.334: [CMS-concurrent-reset-start] 2018-04-12T13:48:38.462+0800: 15590.377: [CMS-concurrent-reset: 0.044/0.044 secs] [Times: user=0.15 sys=0.10, real=0.04 secs]階段7:Concurrent Reset階段
這個(gè)階段也是并發(fā)執(zhí)行的,它會(huì)重設(shè) CMS 內(nèi)部的數(shù)據(jù)結(jié)構(gòu),為下次的 GC 做準(zhǔn)備。Full GC頻繁發(fā)生怎么辦?
排查方向:
1、根據(jù)FULLGC日志分析,消耗在什么階段;
2、JVM參數(shù)設(shè)置不合理;
3、是否有內(nèi)存泄露;
4、對(duì)象的內(nèi)存分配存在問題,大對(duì)象過多;
5、使用jstat、jstack、jmap命令定位;
總結(jié)
以上是生活随笔為你收集整理的【JVM调优】JVM内存管理调优浅谈的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【HTTP协议】HTTP状态码列表大全
- 下一篇: 【面试题】使用 HashMap 还是 T