JVM面試突擊
JDK,JRE以及JVM的關(guān)系
我們的編譯器到底干了什么事?
僅僅是將我們的 .java 文件轉(zhuǎn)換成了 .class 文件,實(shí)際上就是文件格式的轉(zhuǎn)換,對(duì)等信息轉(zhuǎn)換。
類加載機(jī)制是什么?
所謂類加載機(jī)制就是
虛擬機(jī)把Class文件加載到內(nèi)存 并對(duì)數(shù)據(jù)進(jìn)行校驗(yàn),轉(zhuǎn)換解析和初始化 形成可以虛擬機(jī)直接使用的Java類型,即java.lang.Class
裝載(Load)
ClassFile— 字節(jié)流 ---- 類加載器
查找和導(dǎo)入class文件
(1)通過(guò)一個(gè)類的全限定名獲取定義此類的二進(jìn)制字節(jié)流
(2)將這個(gè)字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)
(3)在Java堆中生成一個(gè)代表這個(gè)類的java.lang.Class對(duì)象,作為對(duì)方法區(qū)中這些數(shù)據(jù)的訪問(wèn)入口
鏈接(Link)
驗(yàn)證(Verify)
保證被加載類的正確性
- 文件格式驗(yàn)證
- 元數(shù)據(jù)驗(yàn)證
- 字節(jié)碼驗(yàn)證
- 符號(hào)引用驗(yàn)證
準(zhǔn)備(Prepare)
為類的靜態(tài)變量分配內(nèi)存,并將其初始化為默認(rèn)值
public class Demo1 {
private static int i;
public static void main(String[] args) {
// 正常打印出0,因?yàn)殪o態(tài)變量i在準(zhǔn)備階段會(huì)有默認(rèn)值0
System.out.println(i);
}
}
public class Demo2 {
public static void main(String[] args) {
// 編譯通不過(guò),因?yàn)榫植孔兞繘](méi)有賦值不能被使用
int i;
System.out.println(i);
}
}
解析(Resolve)
把類中的符號(hào)引用轉(zhuǎn)換為直接引用
符號(hào)引用就是一組符號(hào)來(lái)描述目標(biāo),可以是任何字面量。 直接引用就是直接指向目標(biāo)的指針、相對(duì)偏移量或一個(gè)間接定位到目標(biāo)的句柄。
解析階段是虛擬機(jī)將常量池內(nèi)的符號(hào)引用替換為直接引用的過(guò)程。
解析動(dòng)作主要針對(duì)類或接口、字段、類方法、接口方法、方法類型、方法句柄和調(diào)用限定符7類符號(hào)引用進(jìn)
行。
初始化(Initialize)
對(duì)類的靜態(tài)變量,靜態(tài)代碼塊執(zhí)行初始化操作 執(zhí)行了Clinit方法
類加載器有哪些?
類加載器ClassLoader
在裝載(Load)階段,其中第(1)步:通過(guò)類的全限定名獲取其定義的二進(jìn)制字節(jié)流,需要借助類裝載器完成,顧名思義,就是用來(lái)裝載Class文件的。
圖解:
1)Bootstrap ClassLoader 負(fù)責(zé)加載 JAVA_HOME中 jre/lib/rt.jar 里所有的class或Xbootclassoath選項(xiàng)指定的jar包。由C++實(shí)現(xiàn),不是ClassLoader子類。
2)Extension ClassLoader 負(fù)責(zé)加載java平臺(tái)中擴(kuò)展功能的一些jar包,包括`$$JAVA_HOME中jre/lib/*.jar 或 -Djava.ext.dirs指定目錄下的jar包。
3)App ClassLoader 負(fù)責(zé)加載classpath中指定的jar包及 Djava.class.path 所指定目錄下的類和jar包。
4)Custom ClassLoader 通過(guò)java.lang.ClassLoader的子類自定義加載class,屬于應(yīng)用程序根據(jù)自身需要自定義的ClassLoader,如tomcat、jboss都會(huì)根據(jù)j2ee規(guī)范自行實(shí)現(xiàn)ClassLoader。
雙親委派以及打破雙親委派 父類委托機(jī)制
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
sun.misc.PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
向上檢查 向下委派
打破雙親委派:
3種方式
復(fù)寫
SPI Service Provider Interface 接口
OSGI 熱更新 熱部署 外包中的外包
運(yùn)行時(shí)數(shù)據(jù)區(qū)
(1)方法區(qū)是各個(gè)線程共享的內(nèi)存區(qū)域,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建
The Java Virtual Machine has a method area that is shared among all Java Virtual Machine threads.
The method area is created on virtual machine start-up.
(2)雖然Java虛擬機(jī)規(guī)范把方法區(qū)描述為堆的一個(gè)邏輯部分,但是它卻又一個(gè)別名叫做Non-Heap(非堆),目的是與Java堆區(qū)分開來(lái)
Although the method area is logically part of the heap,......
(3)用于存儲(chǔ)已被虛擬機(jī)加載的類信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)
It stores per-class structures such as the run-time constant pool, field and method data, and the code for methods and constructors, including the special methods (§2.9) used in class and instance initialization and interface initialization.
(4)當(dāng)方法區(qū)無(wú)法滿足內(nèi)存分配需求時(shí),將拋出OutOfMemoryError異常
If memory in the method area cannot be made available to satisfy an allocation request, the Java Virtual Machine throws an OutOfMemoryError.
注意:JVM運(yùn)行時(shí)數(shù)據(jù)區(qū)是一種規(guī)范,真正的實(shí)現(xiàn)在JDK 8中就是Metaspace,在JDK6或7中就是Perm Space
Heap(堆)
(1)Java堆是Java虛擬機(jī)所管理內(nèi)存中最大的一塊,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建,被所有線程共享。
(2)Java對(duì)象實(shí)例以及數(shù)組都在堆上分配。
Java Virtual Machine Stacks(虛擬機(jī)棧)
假如目前的階段是初始化完成了,后續(xù)做啥呢?肯定是Use使用咯,不用的話這樣折騰來(lái)折騰去有什么意義?那怎樣才能被使用到?換句話說(shuō)里面內(nèi)容怎樣才能被執(zhí)行?比如通過(guò)主函數(shù)main調(diào)用其他方法,這種方式實(shí)際上是main線程執(zhí)行之后調(diào)用的方法,即要想使用里面的各種內(nèi)容,得要以線程為單位,執(zhí)行相應(yīng)的方法才行。**那一個(gè)線程執(zhí)行的狀態(tài)如何維護(hù)?一個(gè)線程可以執(zhí)行多少個(gè)方法?這樣的關(guān)系怎么維護(hù)呢?
(1)虛擬機(jī)棧是一個(gè)線程執(zhí)行的區(qū)域,保存著一個(gè)線程中方法的調(diào)用狀態(tài)。換句話說(shuō),一個(gè)Java線程的運(yùn)行狀態(tài),由一個(gè)虛擬機(jī)棧來(lái)保存,所以虛擬機(jī)??隙ㄊ蔷€程私有的,獨(dú)有的,隨著線程的創(chuàng)建而創(chuàng)建。
Each Java Virtual Machine thread has a private Java Virtual Machine stack, created at the same time as the thread.
(2)每一個(gè)被線程執(zhí)行的方法,為該棧中的棧幀,即每個(gè)方法對(duì)應(yīng)一個(gè)棧幀。
調(diào)用一個(gè)方法,就會(huì)向棧中壓入一個(gè)棧幀;一個(gè)方法調(diào)用完成,就會(huì)把該棧幀從棧中彈出。
A Java Virtual Machine stack stores frames (§2.6).
A new frame is created each time a method is invoked. A frame is destroyed when its method invocation completes.
棧幀:每個(gè)棧幀對(duì)應(yīng)一個(gè)被調(diào)用的方法,可以理解為一個(gè)方法的運(yùn)行空間。
每個(gè)棧幀中包括局部變量表(Local Variables)、操作數(shù)棧(Operand Stack)、指向運(yùn)行時(shí)常量池的引用(A reference to the run-time constant pool)、方法返回地址(Return Address)和附加信息。
局部變量表:方法中定義的局部變量以及方法的參數(shù)存放在這張表中
局部變量表中的變量不可直接使用,如需要使用的話,必須通過(guò)相關(guān)指令將其加載至操作數(shù)棧中作為操作數(shù)使用。
操作數(shù)棧:以壓棧和出棧的方式存儲(chǔ)操作數(shù)的
動(dòng)態(tài)鏈接:每個(gè)棧幀都包含一個(gè)指向運(yùn)行時(shí)常量池中該棧幀所屬方法的引用,持有這個(gè)引用是為了支持方法調(diào)用過(guò)程中的動(dòng)態(tài)連接(Dynamic Linking)。
方法返回地址:當(dāng)一個(gè)方法開始執(zhí)行后,只有兩種方式可以退出,一種是遇到方法返回的字節(jié)碼指令;一種是遇見異常,并且這個(gè)異常沒(méi)有在方法體內(nèi)得到處理。
棧幀的結(jié)構(gòu)
局部變量表:方法中的局部變量以及方法的參數(shù)會(huì)存放在這
操作數(shù)棧:也是一個(gè)棧,他是以壓棧以及出棧的方式來(lái)存儲(chǔ)操作數(shù)的
int a = 1;
int b = 1 ;
int c = a + b;
方法的返回地址:
一個(gè)方法執(zhí)行之后,只有兩種情況可以退出,遇到返回的字節(jié)碼指令 異常返回
動(dòng)態(tài)鏈接:動(dòng)態(tài)鏈接將這些符號(hào)方法引用轉(zhuǎn)換為具體的方法引用
符號(hào)引用轉(zhuǎn)化成直接引用
void a(){
b();
}
void b(){
c();
}
void c(){
XXXXX
}
堆為什么進(jìn)行分代設(shè)計(jì)
老年代的擔(dān)保機(jī)制
為什么Eden:S0:S1 是8:1:1
對(duì)象的創(chuàng)建以及分配過(guò)程
方法區(qū)與元數(shù)據(jù)區(qū)以及持久代到底是什么關(guān)系?
Full GC = young GC + Old GC + Meta Space GC
規(guī)范:方法區(qū)
實(shí)現(xiàn):
JDK1.7之前 永久代 持久代 Perm Space 類的總數(shù) 常量池大小 方法的數(shù)量
JDK1.8以及其之后 元空間 元數(shù)據(jù)區(qū) MetaSpace
JVMTI 開后門
對(duì)象的內(nèi)存布局
為了加快CPU的讀取效率 哪怕是引用類型 也只是讀取一次
對(duì)象被判定為不可達(dá)對(duì)象之后就“死”了嗎
垃圾收集算法
已經(jīng)能夠確定一個(gè)對(duì)象為垃圾之后,接下來(lái)要考慮的就是回收,怎么回收呢?得要有對(duì)應(yīng)的算法,下面介紹常見的垃圾回收算法。高效 健壯
標(biāo)記-清除(Mark-Sweep)
- 標(biāo)記
找出內(nèi)存中需要回收的對(duì)象,并且把它們標(biāo)記出來(lái)
此時(shí)堆中所有的對(duì)象都會(huì)被掃描一遍,從而才能確定需要回收的對(duì)象,比較耗時(shí)
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-wC4iBzmK-1691042931152)(file://E:\桌面\yzt\筆記課件\JVM\3天JVM訓(xùn)練營(yíng)\資料+筆記\images\25.png?lastModify=1646720640)]
- 清除
清除掉被標(biāo)記需要回收的對(duì)象,釋放出對(duì)應(yīng)的內(nèi)存空間
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-L0gjWEyz-1691042931153)(file://E:\桌面\yzt\筆記課件\JVM\3天JVM訓(xùn)練營(yíng)\資料+筆記\images\26.png?lastModify=1646720640)]
缺點(diǎn)
標(biāo)記清除之后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片,空間碎片太多可能會(huì)導(dǎo)致以后在程
序運(yùn)行過(guò)程中需要分配較大對(duì)象時(shí),無(wú)法找到足夠的連續(xù)內(nèi)存而不得不提前觸發(fā)另一次垃圾收集動(dòng)作。
(1)標(biāo)記和清除兩個(gè)過(guò)程都比較耗時(shí),效率不高
(2)會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片,空間碎片太多可能會(huì)導(dǎo)致以后在程序運(yùn)行過(guò)程中需要分配較大對(duì)象時(shí),無(wú)法找到足夠的連續(xù)內(nèi)存而不得不提前觸發(fā)另一次垃圾收集動(dòng)作。
標(biāo)記-復(fù)制(Mark-Copying)
將內(nèi)存劃分為兩塊相等的區(qū)域,每次只使用其中一塊,如下圖所示:
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-LgBR1sH3-1691042931154)(file://E:\桌面\yzt\筆記課件\JVM\3天JVM訓(xùn)練營(yíng)\資料+筆記\images\27.png?lastModify=1646720640)]
當(dāng)其中一塊內(nèi)存使用完了,就將還存活的對(duì)象復(fù)制到另外一塊上面,然后把已經(jīng)使用過(guò)的內(nèi)存空間一次清除掉。
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-9XCaY8m1-1691042931171)(file://E:\桌面\yzt\筆記課件\JVM\3天JVM訓(xùn)練營(yíng)\資料+筆記\images\28.png?lastModify=1646720640)]
缺點(diǎn):
空間利用率降低。
標(biāo)記-整理(Mark-Compact)
復(fù)制收集算法在對(duì)象存活率較高時(shí)就要進(jìn)行較多的復(fù)制操作,效率將會(huì)變低。更關(guān)鍵的是,如果不想浪費(fèi)50%的空間,就需要有額外的空間進(jìn)行分配擔(dān)保,以應(yīng)對(duì)被使用的內(nèi)存中所有對(duì)象都有100%存活的極端情況,所以老年代一般不能直接選用這種算法。
標(biāo)記過(guò)程仍然與"標(biāo)記-清除"算法一樣,但是后續(xù)步驟不是直接對(duì)可回收對(duì)象進(jìn)行清理,而是讓所有存活的對(duì)象都向一端移動(dòng),然后直接清理掉端邊界以外的內(nèi)存。
其實(shí)上述過(guò)程相對(duì)"復(fù)制算法"來(lái)講,少了一個(gè)"保留區(qū)"
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-HUZgY6eZ-1691042931174)(file://E:\桌面\yzt\筆記課件\JVM\3天JVM訓(xùn)練營(yíng)\資料+筆記\images\25.png?lastModify=1646720640)]
讓所有存活的對(duì)象都向一端移動(dòng),清理掉邊界意外的內(nèi)存。
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-9VWFEUsw-1691042931177)(file://E:\桌面\yzt\筆記課件\JVM\3天JVM訓(xùn)練營(yíng)\資料+筆記\images\29.png?lastModify=1646720640)]
分代收集算法
既然上面介紹了3中垃圾收集算法,那么在堆內(nèi)存中到底用哪一個(gè)呢?
Young區(qū):復(fù)制算法(對(duì)象在被分配之后,可能生命周期比較短,Young區(qū)復(fù)制效率比較高)
Old區(qū):標(biāo)記清除或標(biāo)記整理(Old區(qū)對(duì)象存活時(shí)間比較長(zhǎng),復(fù)制來(lái)復(fù)制去沒(méi)必要,不如做個(gè)標(biāo)記再清理)
垃圾收集器
如果說(shuō)收集算法是內(nèi)存回收的方法論,那么垃圾收集器就是內(nèi)存回收的具體實(shí)現(xiàn)。
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-26EwYw9f-1691042931178)(file://E:\桌面\yzt\筆記課件\JVM\3天JVM訓(xùn)練營(yíng)\資料+筆記\images\30.png?lastModify=1646736013)]
- Serial
Serial收集器是最基本、發(fā)展歷史最悠久的收集器,曾經(jīng)(在JDK1.3.1之前)是虛擬機(jī)新生代收集的唯一選擇。
它是一種單線程收集器,不僅僅意味著它只會(huì)使用一個(gè)CPU或者一條收集線程去完成垃圾收集工作,更重要的是其在進(jìn)行垃圾收集的時(shí)候需要暫停其他線程。
優(yōu)點(diǎn):簡(jiǎn)單高效,擁有很高的單線程收集效率
缺點(diǎn):收集過(guò)程需要暫停所有線程
算法:復(fù)制算法
適用范圍:新生代
應(yīng)用:Client模式下的默認(rèn)新生代收集器
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-uDfFyrBL-1691042931180)(file://E:\桌面\yzt\筆記課件\JVM\3天JVM訓(xùn)練營(yíng)\資料+筆記\images\31.png?lastModify=1646736013)]
- Serial Old
Serial Old收集器是Serial收集器的老年代版本,也是一個(gè)單線程收集器,不同的是采用"標(biāo)記-整理算法",運(yùn)行過(guò)程和Serial收集器一樣。
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-fUfMen0Z-1691042931181)(file://E:\桌面\yzt\筆記課件\JVM\3天JVM訓(xùn)練營(yíng)\資料+筆記\images\32.png?lastModify=1646736013)]
- ParNew
可以把這個(gè)收集器理解為Serial收集器的多線程版本。
優(yōu)點(diǎn):在多CPU時(shí),比Serial效率高。
缺點(diǎn):收集過(guò)程暫停所有應(yīng)用程序線程,單CPU時(shí)比Serial效率差。
算法:復(fù)制算法
適用范圍:新生代
應(yīng)用:運(yùn)行在Server模式下的虛擬機(jī)中首選的新生代收集器
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-fbsMz1tA-1691042931183)(file://E:\桌面\yzt\筆記課件\JVM\3天JVM訓(xùn)練營(yíng)\資料+筆記\images\33.png?lastModify=1646736013)]
- Parallel Scavenge
Parallel Scavenge收集器是一個(gè)新生代收集器,它也是使用復(fù)制算法的收集器,又是并行的多線程收集器,看上去和ParNew一樣,但是Parallel Scanvenge更關(guān)注系統(tǒng)的吞吐量。
吞吐量=運(yùn)行用戶代碼的時(shí)間/(運(yùn)行用戶代碼的時(shí)間+垃圾收集時(shí)間)
比如虛擬機(jī)總共運(yùn)行了100分鐘,垃圾收集時(shí)間用了1分鐘,吞吐量=(100-1)/100=99%。
若吞吐量越大,意味著垃圾收集的時(shí)間越短,則用戶代碼可以充分利用CPU資源,盡快完成程序的運(yùn)算任務(wù)。
-XX:MaxGCPauseMillis控制最大的垃圾收集停頓時(shí)間,
-XX:GCRatio直接設(shè)置吞吐量的大小。
- Parallel Old
Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多線程和標(biāo)記-整理算法進(jìn)行垃圾回收,也是更加關(guān)注系統(tǒng)的吞吐量。
- CMS
官網(wǎng)
: https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/cms.html#concurrent_mark_sweep_cms_collectorCMS(Concurrent Mark Sweep)收集器是一種以獲取
最短回收停頓時(shí)間
為目標(biāo)的收集器。采用的是"標(biāo)記-清除算法",整個(gè)過(guò)程分為4步
(1)初始標(biāo)記 CMS initial mark 標(biāo)記GC Roots直接關(guān)聯(lián)對(duì)象,不用Tracing,速度很快
(2)并發(fā)標(biāo)記 CMS concurrent mark 進(jìn)行GC Roots Tracing
(3)重新標(biāo)記 CMS remark 修改并發(fā)標(biāo)記因用戶程序變動(dòng)的內(nèi)容
(4)并發(fā)清除 CMS concurrent sweep 清除不可達(dá)對(duì)象回收空間,同時(shí)有新垃圾產(chǎn)生,留著下次清理稱為浮動(dòng)垃圾
由于整個(gè)過(guò)程中,并發(fā)標(biāo)記和并發(fā)清除,收集器線程可以與用戶線程一起工作,所以總體上來(lái)說(shuō),CMS收集器的內(nèi)存回收過(guò)程是與用戶線程一起并發(fā)地執(zhí)行的。
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-kH7cmrKr-1691042931184)(file://E:\桌面\yzt\筆記課件\JVM\3天JVM訓(xùn)練營(yíng)\資料+筆記\images\34.png?lastModify=1646736013)]
優(yōu)點(diǎn):并發(fā)收集、低停頓
缺點(diǎn):產(chǎn)生大量空間碎片、并發(fā)階段會(huì)降低吞吐量
- G1(Garbage-First)
官網(wǎng)
: https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/g1_gc.html#garbage_first_garbage_collection**使用G1收集器時(shí),Java堆的內(nèi)存布局與就與其他收集器有很大差別,它將整個(gè)Java堆劃分為多個(gè)大小相等的獨(dú)立區(qū)域(Region),雖然還保留有新生代和老年代的概念,但新生代和老年代不再是物理隔離的了,它們都是一部分Region(不需要連續(xù))的集合。 **
每個(gè)Region大小都是一樣的,可以是1M到32M之間的數(shù)值,但是必須保證是2的n次冪
如果對(duì)象太大,一個(gè)Region放不下[超過(guò)Region大小的50%],那么就會(huì)直接放到H中
設(shè)置Region大?。?XX:G1HeapRegionSize=M
所謂Garbage-Frist,其實(shí)就是優(yōu)先回收垃圾最多的Region區(qū)域
(1)分代收集(仍然保留了分代的概念) (2)空間整合(整體上屬于“標(biāo)記-整理”算法,不會(huì)導(dǎo)致空間碎片) (3)可預(yù)測(cè)的停頓(比CMS更先進(jìn)的地方在于能讓使用者明確指定一個(gè)長(zhǎng)度為M毫秒的時(shí)間片段內(nèi),消耗在垃圾收集上的時(shí)間不得超過(guò)N毫秒)
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-0nHTjZxP-1691042931186)(file://E:\桌面\yzt\筆記課件\JVM\3天JVM訓(xùn)練營(yíng)\資料+筆記\images\35.png?lastModify=1646736013)]
工作過(guò)程可以分為如下幾步
初始標(biāo)記(Initial Marking) 標(biāo)記以下GC Roots能夠關(guān)聯(lián)的對(duì)象,并且修改TAMS的值,需要暫停用戶線程
并發(fā)標(biāo)記(Concurrent Marking) 從GC Roots進(jìn)行可達(dá)性分析,找出存活的對(duì)象,與用戶線程并發(fā)執(zhí)行
最終標(biāo)記(Final Marking) 修正在并發(fā)標(biāo)記階段因?yàn)橛脩舫绦虻牟l(fā)執(zhí)行導(dǎo)致變動(dòng)的數(shù)據(jù),需暫停用戶線程
篩選回收(Live Data Counting and Evacuation) 對(duì)各個(gè)Region的回收價(jià)值和成本進(jìn)行排序,根據(jù)用戶所期望的GC停頓時(shí)間制定回收計(jì)劃
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-RU7Y1iVd-1691042931187)(file://E:\桌面\yzt\筆記課件\JVM\3天JVM訓(xùn)練營(yíng)\資料+筆記\images\36.png?lastModify=1646736013)]
- ZGC
官網(wǎng)
: https://docs.oracle.com/en/java/javase/11/gctuning/z-garbage-collector1.html#GUID-A5A42691-095E-47BA-B6DC-FB4E5FAA43D0JDK11新引入的ZGC收集器,不管是物理上還是邏輯上,ZGC中已經(jīng)不存在新老年代的概念了
會(huì)分為一個(gè)個(gè)page,當(dāng)進(jìn)行GC操作時(shí)會(huì)對(duì)page進(jìn)行壓縮,因此沒(méi)有碎片問(wèn)題
只能在64位的linux上使用,目前用得還比較少
(1)可以達(dá)到10ms以內(nèi)的停頓時(shí)間要求
(2)支持TB級(jí)別的內(nèi)存文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-628766.html
(3)堆內(nèi)存變大后停頓時(shí)間還是在10ms以內(nèi)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-628766.html
到了這里,關(guān)于JVM面試突擊1的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!