您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“有哪些學(xué)習(xí)Java GC的基礎(chǔ)”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“有哪些學(xué)習(xí)Java GC的基礎(chǔ)”吧!
淺談基礎(chǔ)
1.1 運(yùn)行時(shí)數(shù)據(jù)區(qū)(Java 1.8)
1.2 垃圾收集算法
1.3 垃圾收集器
解析 GC 日志
JVM 監(jiān)控工具
Linux 監(jiān)控相關(guān)
(Program Counter Register)【線程隔離】
可簡(jiǎn)單理解為當(dāng)前線程所執(zhí)行的字節(jié)碼行號(hào)指示器;
如果是java方法,計(jì)數(shù)器記錄指向虛擬機(jī)字節(jié)碼指令地址;如果是native方法,計(jì)數(shù)器值為undefined;
【異常相關(guān)】唯一一個(gè)沒(méi)規(guī)定OOM的區(qū)域。
(VM Stack)【線程隔離】
其描述的是Java方法執(zhí)行的內(nèi)存模型:【重點(diǎn)】每個(gè)方法執(zhí)行的過(guò)程都會(huì)創(chuàng)建一個(gè)棧幀(Stack Frame)用于存儲(chǔ)局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法出口等信息。方法調(diào)用到執(zhí)行結(jié)束,對(duì)應(yīng)著一個(gè)棧幀在虛擬機(jī)棧中入棧到出棧的過(guò)程;
【異常相關(guān)】如果線程請(qǐng)求的棧深度大于虛擬機(jī)所允許的深度,將拋出StackOverflowError異常。方法每次調(diào)用都會(huì)創(chuàng)建一個(gè)棧幀,然后棧幀壓棧,總不能無(wú)限壓棧吧(初看沒(méi)看懂,搜了下,發(fā)現(xiàn)也有人沒(méi)看懂,心里平衡點(diǎn));
【異常相關(guān)】大部分虛擬機(jī)棧都可以動(dòng)態(tài)擴(kuò)展,如果擴(kuò)展時(shí)無(wú)法申請(qǐng)到足夠的內(nèi)存,就會(huì)OOM。
代碼示例,見(jiàn)文末 code01.StackOverflowError
(Native Method Stack)【線程隔離】
與虛擬機(jī)棧的區(qū)別是,虛擬機(jī)棧執(zhí)行java方法(字節(jié)碼)服務(wù);本非方法棧則為native方法服務(wù);
【異常相關(guān)】StackOverflowError、OOM。
(Heap)【線程共享】
GC堆(垃圾堆),是垃圾收集器管理的主要區(qū)域;
java1.8之后【年輕代、老年代】。
代碼示例,見(jiàn)文末 code02.OOM-heap
(Metaspace)【線程共享】
jvm config example: -XX:MetaspaceSize=8m -XX:MaxMetaspaceSize=50m
元數(shù)據(jù)區(qū)取代了永久代,本質(zhì)上都是方法區(qū)的實(shí)現(xiàn),用來(lái)存放虛擬機(jī)加載的類信息、常量、靜態(tài)變量、JIT編譯后的代碼。
代碼示例,見(jiàn)文末 code03.OOM-metaspace
對(duì)象在否?引用計(jì)數(shù)算法、可達(dá)性分析算法
標(biāo)記-清除算法(先標(biāo)記,再清除,清除后空間不連續(xù),產(chǎn)生大量?jī)?nèi)存碎片)
復(fù)制算法
年輕代:Eden : Survivor = 1:8,會(huì)有10%的內(nèi)存“閑置”;
每次GC后,存活的對(duì)象都會(huì)放在剩余的10%內(nèi)存中,也就是To Survivor;
當(dāng)然,如果剩余的10%內(nèi)存不夠用呢,就需要依賴?yán)夏甏M(jìn)行分配擔(dān)保。
標(biāo)記-整理算法
如果對(duì)象存活率較高,那么復(fù)制算法就不好用了;
標(biāo)記-清除算法之后,將所有存活的對(duì)象都向一端移動(dòng),然后清理掉邊界以外的內(nèi)存。
分代收集算法
典型就是分為新生代和老年代
新生代,存活率低,就使用復(fù)制算法
老年代,存活率高,并且沒(méi)有額外的空間做擔(dān)保,所以使用“標(biāo)記-清除”或者“標(biāo)記-整理”算法
【單線程】歷史悠久,新生代收集器,復(fù)制算法;
GC時(shí)要STW,直到GC完成(你媽媽在打掃衛(wèi)生,你一邊亂扔紙屑,所以必須STW,你得老老實(shí)實(shí)坐著);
Client 模式下默認(rèn)的新生代收集器(與其他單線程收集器相比,簡(jiǎn)單高效)。
【并行多線程】新生代收集器,復(fù)制算法,Serial收集器的多線程版本;
單CPU下,不會(huì)比Serial好;甚至雙CPU都不能100%超越Serial;
Server模式下首選新生代收集器,重要原因是,他能和CMS(真正意義上的并發(fā)收集器)配合工作。
【Throughput】吞吐量?jī)?yōu)先
【并行多線程】新生代收集器,復(fù)制算法;
關(guān)注點(diǎn)不一樣,目標(biāo)為可控的吞吐量(Throughput),其他的關(guān)注點(diǎn)是盡可能縮短GC STW時(shí)間;
吞吐量 = 運(yùn)行用戶代碼時(shí)間 / (運(yùn)行用戶代碼時(shí)間 + GC時(shí)間)
【單線程】老年代收集器,標(biāo)記 - 整理算法;
主要用戶Client 模式下虛擬機(jī);Server模式下,1. JDK1.6以前與PS搭配使用;2. CMC收集器后背預(yù)案。
【Throughput】吞吐量?jī)?yōu)先
【并行多線程】老年代收集器,標(biāo)記 - 整理算法;
jdk1.6以前,如果選了PS,就不能選CMS了,只能選Serial Old;
吞吐量?jī)?yōu)先第一組合。
【并發(fā)多線程】老年代收集器,基于標(biāo)記 - 清除(初始 & 并發(fā) & 重新 標(biāo)記,并發(fā)清除);
關(guān)注點(diǎn)不一樣,目標(biāo)為可控的吞吐量(Throughput),其他的關(guān)注點(diǎn)是盡可能縮短GC STW時(shí)間;
并發(fā)低停頓;缺點(diǎn):CPU資源非常敏感、無(wú)法處理浮動(dòng)垃圾、基于標(biāo)記清除多碎片。
有點(diǎn)多,暫緩。。。
2019-11-04T16:05:43.267+0800: 147.981: [GC (Allocation Failure) [PSYoungGen: 150496K->5938K(147456K)] 198958K->57548K(202752K), 0.0304547 secs] [Times: user=0.05 sys=0.00, real=0.03 secs] Heap after GC invocations=39 (full 3): PSYoungGen total 147456K, used 5938K [0x00000000f6700000, 0x0000000100000000, 0x0000000100000000) eden space 141312K, 0% used [0x00000000f6700000,0x00000000f6700000,0x00000000ff100000) from space 6144K, 96% used [0x00000000ffa00000,0x00000000fffcc8f8,0x0000000100000000) to space 7680K, 0% used [0x00000000ff100000,0x00000000ff100000,0x00000000ff880000) ParOldGen total 55296K, used 51610K [0x00000000e3400000, 0x00000000e6a00000, 0x00000000f6700000) object space 55296K, 93% used [0x00000000e3400000,0x00000000e6666870,0x00000000e6a00000) Metaspace used 80445K, capacity 83414K, committed 83584K, reserved 1122304K class space used 10018K, capacity 10577K, committed 10624K, reserved 1048576K } {Heap before GC invocations=40 (full 4): PSYoungGen total 147456K, used 5938K [0x00000000f6700000, 0x0000000100000000, 0x0000000100000000) eden space 141312K, 0% used [0x00000000f6700000,0x00000000f6700000,0x00000000ff100000) from space 6144K, 96% used [0x00000000ffa00000,0x00000000fffcc8f8,0x0000000100000000) to space 7680K, 0% used [0x00000000ff100000,0x00000000ff100000,0x00000000ff880000) ParOldGen total 55296K, used 51610K [0x00000000e3400000, 0x00000000e6a00000, 0x00000000f6700000) object space 55296K, 93% used [0x00000000e3400000,0x00000000e6666870,0x00000000e6a00000) Metaspace used 80445K, capacity 83414K, committed 83584K, reserved 1122304K class space used 10018K, capacity 10577K, committed 10624K, reserved 1048576K =====================分割線========================== 2019-11-04T16:05:43.298+0800: 148.011: [Full GC (Ergonomics) [PSYoungGen: 5938K->0K(147456K)] [ParOldGen: 51610K->48605K(83968K)] 57548K->48605K(231424K), [Metaspace: 80445K->80445K(1122304K)], 0.3256949 secs] [Times: user=0.55 sys=0.00, real=0.32 secs] =====================。。。==========================
2019-11-04T16:05:43.267+0800: 147.981: [GC (Allocation Failure) [PSYoungGen: 150496K->5938K(147456K)] 198958K->57548K(202752K), 0.0304547 secs] [Times: user=0.05 sys=0.00, real=0.03 secs]
2019-11-04T16:05:43.298+0800: 148.011: [Full GC (Ergonomics) [PSYoungGen: 5938K->0K(147456K)] [ParOldGen: 51610K->48605K(83968K)] 57548K->48605K(231424K), [Metaspace: 80445K->80445K(1122304K)], 0.3256949 secs] [Times: user=0.55 sys=0.00, real=0.32 secs]
147.981
和 148.011
: JVM啟動(dòng)以來(lái)經(jīng)過(guò)的秒數(shù)
GC
和 Full GC
: 表示垃圾收集停頓類型。注意:不是用來(lái)區(qū)分新生代還是老年代的
GC (Allocation Failure)
Allocation Failure 指分配失敗,也即空間不足;
Full GC (Ergonomics)
Ergonomics 可以理解為自適應(yīng),表示自動(dòng)的調(diào)節(jié)STW時(shí)間和吞吐量之間的平衡;
Full GC (System)
調(diào)用 System.gc()
觸發(fā)的GC。
[PSYoungGen: 150496K->5938K(147456K)]
PSYoungGen,PS表示Parallel Scavenge收集器
DefNew(Default New Generation),也即使用Serial收集器
[ParOldGen: 51610K->48605K(83968K)]
ParOldGen,ParOld表示Parallel Old收集器,吞吐量?jī)?yōu)先
[XXXXXX: 150496K->5938K(147456K)]
150496K->5938K(147456K)
GC前該內(nèi)存區(qū)域已使用容量 -> GC后該內(nèi)存區(qū)域已使用容量(該內(nèi)存區(qū)域總?cè)萘?
198958K->57548K(202752K)
GC前Java堆已使用容量 -> GC后Java堆已使用容量(Java堆總?cè)萘?
0.0304547 secs
GC耗時(shí)合計(jì)(secs秒)
[Times: user=0.05 sys=0.00, real=0.03 secs]
用戶態(tài)CPU耗時(shí)、內(nèi)核態(tài)CPU耗時(shí)和墻鐘時(shí)間
CPU時(shí)間與墻鐘時(shí)間區(qū)別:墻鐘時(shí)間包括各種非運(yùn)算等待耗時(shí),例如等待磁盤、線程阻塞;
當(dāng)多CPU或者多核的話,多線程會(huì)疊加這些CPU時(shí)間,所以u(píng)ser或sys超過(guò)real是完全正常的。
public class StackOverflowMain { public static void main(String[] args) { // will throw java.lang.StackOverflowError Test test = new Test(); try { test.increment(); } catch (StackOverflowError e) { System.out.println("sof error, this count is " + test.count); e.printStackTrace(); } } static class Test { private static int count; void increment() { count++; increment(); } } }
public class OOMMain { private static String STR = "string"; /** * -verbose:gc -XX:+HeapDumpOnOutOfMemoryError * -XX:HeapDumpPath=C:\\Users\\User\\Desktop\\gc * will throw oom by Java heap space */ public static void main(String[] args) { List<String> list = new ArrayList<>(); while (true) { list.add(STR += STR); } } }
public class OOMByCglibMain { /** * -verbose:gc -XX:+HeapDumpOnOutOfMemoryError * -XX:HeapDumpPath=C:\\Users\\User\\Desktop\\gc * -XX:MetaspaceSize=9m -XX:MaxMetaspaceSize=9m * will throw oom by Metaspace */ public static void main(String[] args) { ClassLoadingMXBean loadingBean = ManagementFactory.getClassLoadingMXBean(); while (true) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(OOMByCglibMain.class); enhancer.setCallbackTypes(new Class[]{Dispatcher.class, MethodInterceptor.class}); enhancer.setCallbackFilter(new CallbackFilter() { @Override public int accept(Method method) { return 1; } @Override public boolean equals(Object obj) { return super.equals(obj); } }); Class clazz = enhancer.createClass(); System.out.println(clazz.getName()); //顯示數(shù)量信息(共加載過(guò)的類型數(shù)目,當(dāng)前還有效的類型數(shù)目,已經(jīng)被卸載的類型數(shù)目) System.out.println("total: " + loadingBean.getTotalLoadedClassCount()); System.out.println("active: " + loadingBean.getLoadedClassCount()); System.out.println("unloaded: " + loadingBean.getUnloadedClassCount()); } } }
到此,相信大家對(duì)“有哪些學(xué)習(xí)Java GC的基礎(chǔ)”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。