JVM架構(gòu)和GC垃圾回收機制詳解
JVM架構(gòu)圖分析
下圖:參考網(wǎng)絡(luò)+書籍履恩,如有侵權(quán)請見諒 (想了解Hadoop內(nèi)存溢出請看: Hadoop內(nèi)存溢出(OOM)分類撒桨、參數(shù)調(diào)優(yōu)化)
類加載器將類對象加載到堆中,而方法區(qū)存放類的版本沐鼠、字段成洗、方法印机、接口和常量池(存儲字面量和符號引用)。
符號引用包括:1鞭衩、類的權(quán)限定名学搜;2、字段名和屬性论衍;3瑞佩、方法名和屬性。
(1)類加載器子系統(tǒng)(2)運行時數(shù)據(jù)區(qū)(3)執(zhí)行引擎
1. 類加載器子系統(tǒng)
Java的動態(tài)類加載功能是由類加載器子系統(tǒng)處理饲齐。當它在運行時(不是編譯時)首次引用一個類時钉凌,它加載、鏈接并初始化該類文件捂人。
1.1?加載
類由此組件加載御雕。啟動類加載器?(BootStrap class Loader)、擴展類加載器(Extension class Loader)和應(yīng)用程序類加載器(Application class Loader)?這三種類加載器幫助完成類的加載滥搭。
1.? 啟動類加載器?–?負責從啟動類路徑中加載類酸纲,無非就是rt.jar。這個加載器會被賦予最高優(yōu)先級瑟匆。
2.? 擴展類加載器?–?負責加載ext?目錄(jre\lib)內(nèi)的類.
3.? 應(yīng)用程序類加載器?–?負責加載應(yīng)用程序級別類路徑闽坡,涉及到路徑的環(huán)境變量等etc.
上述的類加載器會遵循委托層次算法(Delegation Hierarchy Algorithm)加載類文件。
1.2?鏈接
1.? 校驗?– 字節(jié)碼校驗器會校驗生成的字節(jié)碼是否正確愁溜,如果校驗失敗疾嗅,我們會得到校驗錯誤。
2.? 準備?–?分配內(nèi)存并初始化默認值給所有的靜態(tài)變量冕象。
3.? 解析?–?所有符號內(nèi)存引用被方法區(qū)(Method Area)的原始引用所替代代承。
1.3?初始化
這是類加載的最后階段,這里所有的靜態(tài)變量會被賦初始值,?并且靜態(tài)塊將被執(zhí)行渐扮。
2.?運行時數(shù)據(jù)區(qū)(Runtime Data Area)
The 運行時數(shù)據(jù)區(qū)域被劃分為5個主要組件:
2.1 方法區(qū)(Method Area)
所有類級別數(shù)據(jù)將被存儲在這里论悴,包括靜態(tài)變量掖棉。每個JVM只有一個方法區(qū),它是一個共享的資源膀估。
2.2 堆區(qū)(Heap Area)
所有的對象和它們相應(yīng)的實例變量以及數(shù)組將被存儲在這里幔亥。每個JVM同樣只有一個堆區(qū)。由于方法區(qū)和堆區(qū)的內(nèi)存由多個線程共享察纯,所以存儲的數(shù)據(jù)不是線程安全的帕棉。
2.3 棧區(qū)(Stack Area)
對每個線程會單獨創(chuàng)建一個運行時棧。對每個函數(shù)呼叫會在棧內(nèi)存生成一個棧幀(Stack Frame)饼记。所有的局部變量將在棧內(nèi)存中創(chuàng)建笤昨。棧區(qū)是線程安全的,因為它不是一個共享資源握恳。棧幀被分為三個子實體:
a 局部變量數(shù)組?–?包含多少個與方法相關(guān)的局部變量并且相應(yīng)的值將被存儲在這里瞒窒。
b 操作數(shù)棧?–?如果需要執(zhí)行任何中間操作,操作數(shù)棧作為運行時工作區(qū)去執(zhí)行指令乡洼。
c 幀數(shù)據(jù)?– 方法的所有符號都保存在這里崇裁。在任意異常的情況下,catch塊的信息將會被保存在幀數(shù)據(jù)里面束昵。
如上是JVM三大核心區(qū)域
2.4 PC寄存器
每個線程都有一個單獨的PC寄存器來保存當前執(zhí)行指令的地址拔稳,一旦該指令被執(zhí)行,pc寄存器會被更新至下條指令的地址锹雏。
2.5 本地方法棧
本地方法棧保存本地方法信息巴比。對每一個線程,將創(chuàng)建一個單獨的本地方法棧礁遵。
3. 執(zhí)行引擎
分配給運行時數(shù)據(jù)區(qū)的字節(jié)碼將由執(zhí)行引擎執(zhí)行轻绞。執(zhí)行引擎讀取字節(jié)碼并逐段執(zhí)行。
3.1? 解釋器:
?解釋器能快速的解釋字節(jié)碼佣耐,但執(zhí)行卻很慢政勃。 解釋器的缺點就是,當一個方法被調(diào)用多次,每次都需要重新解釋兼砖。
編譯器
JIT編譯器消除了解釋器的缺點奸远。執(zhí)行引擎利用解釋器轉(zhuǎn)換字節(jié)碼,但如果是重復(fù)的代碼則使用JIT編譯器將全部字節(jié)碼編譯成本機代碼讽挟。本機代碼將直接用于重復(fù)的方法調(diào)用懒叛,這提高了系統(tǒng)的性能。
a.?中間代碼生成器?– 生成中間代碼
b.?代碼優(yōu)化器?– 負責優(yōu)化上面生成的中間代碼
c.?目標代碼生成器?– 負責生成機器代碼或本機代碼
d.? 探測器(Profiler)?– 一個特殊的組件耽梅,負責尋找被多次調(diào)用的方法薛窥。
3.3? 垃圾回收器:
收集并刪除未引用的對象『质可以通過調(diào)用"System.gc()"來觸發(fā)垃圾回收拆檬,但并不保證會確實進行垃圾回收。JVM的垃圾回收只收集哪些由new關(guān)鍵字創(chuàng)建的對象妥凳。所以竟贯,如果不是用new創(chuàng)建的對象,你可以使用finalize函數(shù)來執(zhí)行清理逝钥。
Java本地接口 (JNI):?JNI?會與本地方法庫進行交互并提供執(zhí)行引擎所需的本地庫屑那。
本地方法庫:它是一個執(zhí)行引擎所需的本地庫的集合。
通過一個小程序認識JVM
package com.spark.jvm;
/**
* 當JVM進程啟動的時候艘款,會從類加載路徑中找到包含main方法的入口類HelloJVM
* 找到HelloJVM會直接讀取該文件中的二進制數(shù)據(jù)持际,并且把該類的信息放到運行時的Method內(nèi)存區(qū)域中。
* 然后會定位到HelloJVM中的main方法的字節(jié)碼中哗咆,并開始執(zhí)行Main方法中的指令
* 此時會創(chuàng)建Student實例對象蜘欲,并且使用student來引用該對象(或者說給該對象命名),其內(nèi)幕如下:
* 第一步:JVM會直接到Method區(qū)域中去查找Student類的信息晌柬,此時發(fā)現(xiàn)沒有Student類姥份,就通過類加載器加載該Student類文件;
* 第二步:在JVM的Method區(qū)域中加載并找到了Student類之后會在Heap區(qū)域中為Student實例對象分配內(nèi)存年碘,
* 并且在Student的實例對象中持有指向方法區(qū)域中的Student類的引用(內(nèi)存地址)澈歉;
* 第三步:JVM實例化完成后會在當前線程中為Stack中的reference建立實際的應(yīng)用關(guān)系,此時會賦值給student
* 接下來就是調(diào)用方法
* 在JVM中方法的調(diào)用一定是屬于線程的行為屿衅,也就是說方法調(diào)用本身會發(fā)生在線程的方法調(diào)用棧:
* 線程的方法調(diào)用棧(Method Stack Frames)埃难,每一個方法的調(diào)用就是方法調(diào)用棧中的一個Frame,
* 該Frame包含了方法的參數(shù)涤久,局部變量涡尘,臨時數(shù)據(jù)等 student.sayHello();
*/
public class HelloJVM {
//在JVM運行的時候會通過反射的方式到Method區(qū)域找到入口方法main
public static void main(String[] args) {//main方法也是放在Method方法區(qū)域中的
/**
* student(小寫的)是放在主線程中的Stack區(qū)域中的
* Student對象實例是放在所有線程共享的Heap區(qū)域中的
*/
Student student = new Student("spark");
/**
* 首先會通過student指針(或句柄)(指針就直接指向堆中的對象,句柄表明有一個中間的,student指向句柄响迂,句柄指向?qū)ο螅?/p>
* 找Student對象悟衩,當找到該對象后會通過對象內(nèi)部指向方法區(qū)域中的指針來調(diào)用具體的方法去執(zhí)行任務(wù)
*/
student.sayHello();
}
}
class Student {
// name本身作為成員是放在stack區(qū)域的但是name指向的String對象是放在Heap中
private String name;
public Student(String name) {
this.name = name;
}
//sayHello這個方法是放在方法區(qū)中的
public void sayHello() {
System.out.println("Hello, this is " + this.name);
}
}
JVM三大性能調(diào)優(yōu)參數(shù):-Xms –Xmx –Xss
-Xms –Xmx是對堆的性能調(diào)優(yōu)參數(shù),一般兩個設(shè)置是一樣的栓拜,如果不一樣座泳,當Heap不夠用,會發(fā)生內(nèi)存抖動幕与。一般都調(diào)大這兩個參數(shù)挑势,并且兩個大小一樣。
-Xss是對每一個線程棧的性能調(diào)優(yōu)參數(shù),影響堆棧調(diào)用的深度
實戰(zhàn)演示從OOM推導(dǎo)出JVM GC時候基于的內(nèi)存結(jié)構(gòu):Young Generation(Eden啦鸣、From潮饱、To)、OldGeneration诫给、Permanent Generation
JVMHeap區(qū)域(年輕代香拉、老年代)和方法區(qū)(永久代)結(jié)構(gòu)圖:
從Java GC的角度解讀代碼:程序20行new的Person對象會首先會進入年輕代的Eden中(如果對象太大可能直接進入年老代)啦扬。在GC之前對象是存在Eden和from中的,進行GC的時候Eden中的對象被拷貝到To這樣一個survive空間(survive(幸存)空間:包括from和to凫碌,他們的空間大小是一樣的扑毡,又叫s1和s2)中(有一個拷貝算法),F(xiàn)rom中的對象(算法會考慮經(jīng)過GC幸存的次數(shù))到一定次數(shù)(閾值(如果說每次GC之后這個對象依舊在Survive中存在盛险,GC一次他的Age就會加1瞄摊,默認15就會放到OldGeneration。但是實際情況比較復(fù)雜苦掘,有可能沒有到閾值就從Survive區(qū)域直接到Old Generation區(qū)域换帜。在進行GC的時候會對Survive中的對象進行判斷,Survive空間中有一些對象Age是一樣的鹤啡,也就是經(jīng)過的GC次數(shù)一樣惯驼,年齡相同的這樣一批對象的總和大于等于Survive空間一半的話,這組對象就會進入old Generation中递瑰,(是一種動態(tài)的調(diào)整)))跳座,會被復(fù)制到OldGeneration,如果沒到次數(shù)From中的對象會被復(fù)制到To中泣矛,復(fù)制完成后To中保存的是有效的對象疲眷,Eden和From中剩下的都是無效的對象,這個時候就把Eden和From中所有的對象清空您朽。在復(fù)制的時候Eden中的對象進入To中狂丝,To可能已經(jīng)滿了,這個時候Eden中的對象就會被直接復(fù)制到Old Generation中哗总,F(xiàn)rom中的對象也會直接進入Old Generation中几颜。就是存在這樣一種情況,To比較小讯屈,第一次復(fù)制的時候空間就滿了爽撒,直接進入old Generation中狐树。復(fù)制完成后迫悠,To和From的名字會對調(diào)一下携添,因為Eden和From都是空的,對調(diào)后Eden和To都是空的叛本,下次分配就會分配到Eden沪蓬。一直循環(huán)這個流程。好處:使用對象最多和效率最高的就是在Young Generation中来候,通過From to就避免過于頻繁的產(chǎn)生FullGC(Old Generation滿了一般都會產(chǎn)生FullGC)
虛擬機在進行MinorGC(新生代的GC)的時候跷叉,會判斷要進入OldGeneration區(qū)域?qū)ο蟮拇笮。欠翊笥贠ld Generation剩余空間大小,如果大于就會發(fā)生Full GC云挟。
剛分配對象在Eden中梆砸,如果空間不足嘗試進行GC,回收空間园欣,如果進行了MinorGC空間依舊不夠就放入Old Generation帖世,如果OldGeneration空間還不夠就OOM了。
比較大的對象俊庇,數(shù)組等,大于某值(可配置)就直接分配到老年代鸡挠,(避免頻繁內(nèi)存拷貝)
年輕代和年老代屬于Heap空間的
Permanent Generation(永久代)可以理解成方法區(qū)辉饱,(它屬于方法區(qū))也有可能發(fā)生GC,例如類的實例對象全部被GC了拣展,同時它的類加載器也被GC掉了彭沼,這個時候就會觸發(fā)永久代中對象的GC。
如果OldGeneration滿了就會產(chǎn)生FullGC
滿原因:1备埃,from survive中對象的生命周期到一定閾值
2姓惑,分配的對象直接是大對象
3、由于To 空間不夠按脚,進行GC直接把對象拷貝到年老代(年老代GC時候采用不同的算法)
如果Young Generation大小分配不合理或空間比較小于毙,這個時候?qū)е聦ο蠛苋菀走M入Old Generation中,而Old Generation中回收具體對象的時候速度是遠遠低于Young Generation回收速度辅搬。
因此實際分配要考慮年老代和新生代的比例唯沮,考慮Eden和survives的比例
Permanent Generation中發(fā)生GC的時候也對性能影響非常大,也是Full GC
JVM GC時候核心參數(shù):
-XX:NewRatio –XX:SurvivorRatio –XX:NewSize –XX:MaxNewSize
–XX:NewSize–XX:MaxNewSize指定新生代初始大小和最大大小堪遂。
1介蛉,-XX:NewRatio??? 是年老代 新生代相對的比例,比如NewRatio=2溶褪,表明年老代是新生代的2倍币旧。老年代占了heap的2/3,新生代占了1/3
2猿妈,-XX:SurvivorRatio 配置的是在新生代里面Eden和一個Servive的比例
如果指定NewRatio還可以指定NewSizeMaxNewSize吹菱,如果同時指定了會如何?彭则?毁葱?
NewRatio=2,這個時候新生代會嘗試分配整個Heap大小的1/3的大小贰剥,但是分配的空間不會小于-XX:NewSize也不會大于 –XX:MaxNewSize
3倾剿,-XX:NewSize –XX:MaxNewSize
實際設(shè)置比例還是設(shè)置固定大小,固定大小理論上速度更高。
-XX:NewSize –XX:MaxNewSize理論越大越好前痘,但是整個Heap大小是有限的凛捏,一般年輕代的設(shè)置大小不要超過年老代。
-XX:SurvivorRatio新生代里面Eden和一個Servive的比例芹缔,如果SurvivorRatio是5的話坯癣,也就是Eden區(qū)域是SurviveTo區(qū)域的5倍。Survive由From和To構(gòu)成最欠。結(jié)果就是整個Eden占用了新生代5/7示罗,F(xiàn)rom和To分別占用了1/7,如果分配不合理,Eden太大芝硬,這樣產(chǎn)生對象很順利蚜点,但是進行GC有一部分對象幸存下來,拷貝到To拌阴,空間小绍绘,就沒有足夠的空間,對象會被放在old Generation中迟赃。如果Survive空間大陪拘,會有足夠的空間容納GC后存活的對象,但是Eden區(qū)域小纤壁,會被很快消耗完左刽,這就增加了GC的次數(shù)。
JVM的GC日志解讀:
一酌媒、 JVM YoungGeneration下MinorGC日志詳解
[GC (Allocation Failure) [PSYoungGen:2336K->288K(2560K)] 8274K->6418K(9728K), 0.0112926 secs] [Times:user=0.06 sys=0.00, real=0.01 secs]
PSYoungGen(是新生代類型悠反,新生代日志收集器),2336K表示使用新生代GC前馍佑,占用的內(nèi)存斋否,->288K表示GC后占用的內(nèi)存,(2560K)代表整個新生代總共大小
8274K(GC前整個JVM Heap對內(nèi)存的占用)->6418K(MinorGC后內(nèi)存占用總量)(9728K)(整個堆的大惺没纭)0.0112926 secs(Minor GC消耗的時間)] [Times: user=0.06 sys=0.00, real=0.01 secs] 用戶空間茵臭,內(nèi)核空間時間的消耗,real整個的消耗
二舅世、 JVM的GC日志Full GC日志每個字段徹底詳解
[Full GC (Ergonomics) [PSYoungGen: 984K->425K(2048K)] [ParOldGen:7129K->7129K(7168K)] 8114K->7555K(9216K), [Metaspace:2613K->2613K(1056768K)], 0.1022588 secs] [Times: user=0.56 sys=0.02,real=0.10 secs]
[Full GC (Allocation Failure) [PSYoungGen: 425K->425K(2048K)][ParOldGen: 7129K->7129K(7168K)] 7555K->7555K(9216K), [Metaspace:2613K->2613K(1056768K)], 0.1003696 secs] [Times: user=0.64 sys=0.03,real=0.10 secs]
[Full GC(表明是Full GC) (Ergonomics) [PSYoungGen:FullGC會導(dǎo)致新生代Minor GC產(chǎn)生]984K->425K(2048K)][ParOldGen:(老年代GC)7129K(GC前多大)->7129K(GC后旦委,并沒有降低內(nèi)存占用,因為寫的程序不斷循環(huán)一直有引用)(7168K) (老年代總?cè)萘浚 8114K(GC前占用整個Heap空間大谐恰)->7555K (GC后占用整個Heap空間大杏酢) (9216K) (整個Heap大小,JVM堆的大邪盏汀), [Metaspace: (java6 7是permanentspace查辩,java8改成Metaspace胖笛,類相關(guān)的一些信息) 2613K->2613K(1056768K) (GC前后基本沒變,空間很大)], 0.1022588 secs(GC的耗時宜岛,秒為單位)] [Times: user=0.56 sys=0.02, real=0.10 secs](用戶空間耗時长踊,內(nèi)核空間耗時,真正的耗時時間)
三萍倡、 Java8中的JVM的MetaSpace
Metaspace的使用C語言實現(xiàn)的身弊,使用的是OS的空間,Native Memory Space可動態(tài)的伸縮列敲,可以根據(jù)類加載的信息的情況阱佛,在進行GC的時候進行調(diào)整自身的大小,來延緩下一次GC的到來戴而。
可以設(shè)置Metaspace的大小凑术,如果超過最大大小就會OOM,不設(shè)置如果把整個操作系統(tǒng)的內(nèi)存耗盡了出現(xiàn)OOM填硕,一般會設(shè)置一個足夠大的初始值麦萤,安全其間會設(shè)置最大值鹿鳖。
永久代發(fā)生GC有兩種情況扁眯,類的所有的實例被GC掉,且class load不存翅帜。
對于元數(shù)據(jù)空間 簡化了GC姻檀, class load不存在了就需要進行GC。
三種基本的GC算法基石
一涝滴、 標記/清除算法
內(nèi)存中的對象構(gòu)成一棵樹绣版,當有效的內(nèi)存被耗盡的時候,程序就會停止歼疮,做兩件事杂抽,第一:標記,標記從樹根可達的對象(途中水紅色)韩脏,第二:清除(清楚不可達的對象)缩麸。標記清除的時候有停止程序運行,如果不停止赡矢,此時如果存在新產(chǎn)生的對象杭朱,這個對象是樹根可達的,但是沒有被標記(標記已經(jīng)完成了)吹散,會清除掉弧械。
缺點:遞歸效率低性能低;釋放空間不連續(xù)容易導(dǎo)致內(nèi)存碎片空民;會停止整個程序運行刃唐;
二、 復(fù)制算法
把內(nèi)存分成兩塊區(qū)域:空閑區(qū)域和活動區(qū)域,第一還是標記(標記誰是可達的對象)唁桩,標記之后把可達的對象復(fù)制到空閑區(qū)闭树,將空閑區(qū)變成活動區(qū),同時把以前活動區(qū)對象1荒澡,4清除掉报辱,變成空閑區(qū)。
速度快但耗費空間单山,假定活動區(qū)域全部是活動對象碍现,這個時候進行交換的時候就相當于多占用了一倍空間,但是沒啥用米奸。
三昼接、 標記整理算法
平衡點
標記誰是活躍對象,整理悴晰,會把內(nèi)存對象整理成一課樹一個連續(xù)的空間慢睡,
JVM垃圾回收分代收集算法
綜合了上述算法優(yōu)略
1, 分代GC在新生代的算法:采用了GC的復(fù)制算法铡溪,速度快漂辐,因為新生代一般是新對象,都是瞬態(tài)的用了可能很快被釋放的對象棕硫。
2髓涯, 分代GC在年老代的算法 標記/整理算法,GC后會執(zhí)行壓縮哈扮,整理到一個連續(xù)的空間纬纪,這樣就維護著下一次分配對象的指針,下一次對象分配就可以采用碰撞指針技術(shù)滑肉,將新對象分配在第一個空閑的區(qū)域包各。
JVM垃圾回收器串行、并行靶庙、并發(fā)垃圾回收器概述
1问畅, JVM中不同的垃圾回收器
2, 串行惶洲,并行按声,并發(fā)垃圾回收器(和JVM歷史有關(guān)系,剛開始串行)
Java中Stop-The-World機制簡稱STW恬吕,是在執(zhí)行垃圾收集算法時签则,Java應(yīng)用程序的其他所有線程都被掛起(除了垃圾收集幫助器之外)。Java中一種全局暫皖砹希現(xiàn)象渐裂,全局停頓豺旬,所有Java代碼停止,native代碼可以執(zhí)行柒凉,但不能與JVM交互族阅;這些現(xiàn)象多半是由于gc引起。
JVM中Serial收集器膝捞、ParNew收集器坦刀、Parallel收集器解析
Serial收集器 單線程方式(沒有線程切換開銷,如果受限物理機器單線程可采用)串行且采用stop the world在工作的時候程序會停止
Serial和serial old
ParNew收集器:多線程(多CPU和多Core的環(huán)境中高效)蔬咬,生產(chǎn)環(huán)境對低延時要求高的話鲤遥,就采用ParNew和CMS組合來進行server端的垃圾回收
Parallel 收集器:多線程,并行林艘, 它可以控制JVM吞吐量的大小盖奈,吞吐量優(yōu)先的收集器,一般設(shè)置1%狐援,可設(shè)置程序暫停的時間钢坦,會通過把新生代空間變小,來完成回收啥酱,頻繁的小規(guī)模垃圾回收爹凹,會影響程序吞吐量大小
JVM中CMS收集器解密
低延遲進行垃圾回收,在線服務(wù)和處理速度要求高的情況下很重要
配置:XX:UseConcMarkSweepGC
concurrence(并發(fā)) Mark(標記)Sweep(清理)
低延時
把垃圾回收分成四個階段
CMS-initial-mark初始標記階段會stop the world懈涛,短暫的暫停程序根據(jù)跟對象標記的對象所連接的對象是否可達來標記出哪些可到達
CMS-concurrent-mark并發(fā)標記逛万,根據(jù)上一次標記的結(jié)果確定哪些不可到達泳猬,線程并發(fā)或交替之行批钠,基本不會出現(xiàn)程序暫停。
CMS-remark再次標記得封,會出現(xiàn)程序暫停埋心,所有內(nèi)存那一時刻靜止,確保被全部標記忙上,有可能第二階段之前有可能被標記為垃圾的對象有可能被引用拷呆,在此標記確認。
CMS-concurrent-sweep并發(fā)清理垃圾疫粥,把標記的垃圾清理掉了茬斧,沒有壓縮,有可能產(chǎn)生內(nèi)存碎片梗逮,不連續(xù)的內(nèi)存塊项秉,這時候就不能更好的使用內(nèi)存,可以通過一個參數(shù)配置慷彤,根據(jù)內(nèi)存的情況執(zhí)行壓縮娄蔼。
JVM中G1收集器
可以像CMS收集器一樣怖喻,GC操作與應(yīng)用的現(xiàn)場一起并發(fā)執(zhí)行
緊湊的空閑內(nèi)存區(qū)域且沒有很長的GC停頓時間
需要可預(yù)測的GC暫停耗時
不想犧牲太多吞吐量性能
啟動后不需要請求更大的Java堆
通過案例瞬間理解JVM中PSYoungGen、ParOldGen岁诉、MetaSpace
Heap
PSYoungGen? ? ? total 2560K, used 321K[0x00000007bfd00000, 0x00000007c0000000, 0x00000007c0000000)
? eden space 2048K, 15% used[0x00000007bfd00000,0x00000007bfd50568,0x00000007bff00000)
? from space 512K, 0% used[0x00000007bff00000,0x00000007bff00000,0x00000007bff80000)
? to? space 512K, 0% used[0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
ParOldGen? ? ? total 7168K, used 7097K[0x00000007bf600000, 0x00000007bfd00000, 0x00000007bfd00000)
object space 7168K, 99%used [0x00000007bf600000,0x00000007bfcee7b8,0x00000007bfd00000)
Metaspace? ? ? used 2647K, capacity 4486K, committed4864K, reserved 1056768K
class space? ? used 289K, capacity 386K, committed 512K,reserved 1048576K
PSYoungGen是eden + from
使用MAT對Dump文件進行分析實戰(zhàn)
導(dǎo)出Dump文件
MapReduce過程詳解及其性能優(yōu)化
————————————————
版權(quán)聲明:本文為CSDN博主「aijiudu」的原創(chuàng)文章锚沸,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明涕癣。
原文鏈接:https://blog.csdn.net/aijiudu/article/details/72991993