溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java之JVM的知識(shí)點(diǎn)有哪些

發(fā)布時(shí)間:2022-07-13 10:54:42 來(lái)源:億速云 閱讀:117 作者:iii 欄目:編程語(yǔ)言

今天小編給大家分享一下Java之JVM的知識(shí)點(diǎn)有哪些的相關(guān)知識(shí)點(diǎn),內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識(shí),所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來(lái)了解一下吧。

Java之JVM的知識(shí)點(diǎn)有哪些

一.JVM內(nèi)存區(qū)域劃分

JVM為什么要?jiǎng)澐殖鲞@些區(qū)域呢?JVM內(nèi)存是從操作系統(tǒng)里面申請(qǐng)過來(lái)的,而JVM就根據(jù)功能需求將這些劃分成了一些小的模塊,這樣一塊大的場(chǎng)地就可以劃分成一些小的模塊,然后每個(gè)模塊就負(fù)責(zé)自己的功能就可以了,那接下來(lái)看看這些區(qū)域的功能到底是什么呢!

1.程序計(jì)數(shù)器

程序計(jì)數(shù)器是內(nèi)存中最小的區(qū)域,這里面主要保存了下一條要執(zhí)行的指令的地址在哪里(指令就是字節(jié)碼,一般程序要運(yùn)行,JVM就需要把字節(jié)碼加載出來(lái)放到內(nèi)存中,然后程序再把一條一條的指令從內(nèi)存中取出來(lái)放到CPU上去執(zhí)行,所以必須要記住當(dāng)前執(zhí)行到哪一條指令,以及下一條在哪里,因?yàn)镃PU不是只給一個(gè)進(jìn)程提供服務(wù)的,是給所有的進(jìn)程都提供服務(wù),是并發(fā)式的執(zhí)行程序的,又因?yàn)椴僮飨到y(tǒng)是以線程為單位進(jìn)行調(diào)度執(zhí)行的,所以每個(gè)線程都要有自己的執(zhí)行位置,也就是每一個(gè)線程都需要有一個(gè)程序計(jì)數(shù)器來(lái)記錄位置!)

2.棧

棧里面存放的主要是局部變量和方法調(diào)用信息,只要涉及到新方法的調(diào)用,就會(huì)有"入棧"的操作,每執(zhí)行完成一個(gè)方法,就會(huì)有"出棧"的操作,而且棧也是每個(gè)線程都有一份的
Java之JVM的知識(shí)點(diǎn)有哪些
因此對(duì)于遞歸來(lái)說,一定要控制好遞歸條件,否則很有可能會(huì)出現(xiàn)棧溢出(StackOverflowException)異常的!

3.堆

堆是內(nèi)存中空間最大的區(qū)域,而且堆是每個(gè)進(jìn)程只有一份的,進(jìn)程中的多個(gè)線程公用一個(gè)堆,里面主要存放著new出來(lái)的對(duì)象以及對(duì)象的成員變量,例如String s = new String()如果在方法里面這里的s就是局部變量是在棧上的,如果這個(gè)s是成員變量,就是在堆上的,而后面new String()是對(duì)象的本體,對(duì)象是在堆上的,這是容易混淆的地方,另外堆還有一個(gè)重要的點(diǎn)就是關(guān)于垃圾回收問題,這個(gè)后面再詳細(xì)介紹!

4.方法區(qū)

方法區(qū)中存放的是"類對(duì)象",平常所寫的.java代碼經(jīng)過編譯器翻譯過后就會(huì)變成.class(二進(jìn)制字節(jié)碼),然后.class就會(huì)被加載到內(nèi)存中,也就被JVM構(gòu)造成了類對(duì)象(加載的過程就是稱為"類加載"),而這些類對(duì)象就會(huì)存放到方法區(qū)中,這里面就具體描述了類長(zhǎng)啥樣(類的名字,類的成員及其成員名成員類型,類的方法及其方法名方法類型,以及一些指令…另外類對(duì)象里面還存放了一個(gè)很重要的東西,就是靜態(tài)成員,一般被static修飾的成員就成為了類屬性,而普通的方法被稱為實(shí)例屬性,這是有很大差別的)!

上面所介紹的是JVM中比較常見的區(qū)域,而一些JVM的內(nèi)存區(qū)域劃分不一定是符合實(shí)際情況的,JVM在實(shí)現(xiàn)的過程中區(qū)域的劃分是不盡相同的,不同的廠商不同版本的JVM都是有可能存在差異的,不過對(duì)于我們普通的程序員而講,只要不是去實(shí)現(xiàn)JVM,那么就不需要了解那么深刻,講上面的幾個(gè)常見的區(qū)域加以了解就可以了!


二.JVM類加載機(jī)制

類加載其實(shí)是設(shè)計(jì)一個(gè)運(yùn)行時(shí)環(huán)境的一個(gè)重要的功核心功能,這是非常重量級(jí)的,因此我這里也就簡(jiǎn)單介紹一下!
Java之JVM的知識(shí)點(diǎn)有哪些
上述就是類加載的具體過程,最后面的Using和Unloading就是使用的過程就不介紹了,就介紹一下前面的三個(gè)大的步驟:

1.Loading(加載)

在loading階段就會(huì)先找到對(duì)應(yīng)的.class文件,然后打開并讀取(根據(jù)字節(jié)流).class文件,同時(shí)初步生成一個(gè)類對(duì)象,這個(gè)和完成的類加載(class Loading)是不相同的,不要弄混淆了!
class文件的具體格式(如果要實(shí)現(xiàn)一個(gè)Java編譯器就得按照這樣的格式來(lái)構(gòu)造,實(shí)現(xiàn)JVM就得按照這個(gè)格式來(lái)進(jìn)行加載!):
Java之JVM的知識(shí)點(diǎn)有哪些
觀察這個(gè)格式就可以看到.class文件就把.java文件中的核心信息都表述進(jìn)去了,只不過組織格式上發(fā)生了轉(zhuǎn)變,所以loading環(huán)節(jié)就會(huì)把讀取到的信息,初步填寫到類對(duì)象中

2.Linking(連接)

連接一般就是建立好多個(gè)實(shí)體之間的聯(lián)系

2.1.Verification(驗(yàn)證)

Verification就是一個(gè)校驗(yàn)的過程,主要就是驗(yàn)證讀到的內(nèi)容是不是和規(guī)范中規(guī)定的格式完全匹配,如果發(fā)現(xiàn)讀到的數(shù)據(jù)格式不符合規(guī)范,就會(huì)類加載失敗,并且拋出異常!

2.2.Preparation(準(zhǔn)備)

Preparation階段是正式為定義的變量(靜態(tài)變量,就是static修飾的變量)分配內(nèi)存并設(shè)置類變量初始值的階段,就會(huì)給每個(gè)靜態(tài)變量分配內(nèi)存,并且設(shè)置為0值!

2.3.Resolution(解析)

Resolution階段是Java虛擬機(jī)將常量池內(nèi)的符號(hào)引用替換為直接引用的過程,也就是初始化常量的過程,.class文件中常量是集中放置的,每個(gè)常量會(huì)有一個(gè)編號(hào),而在.class文件中的結(jié)構(gòu)體里初始情況就只是記錄的編號(hào),然后就可以根據(jù)這個(gè)編號(hào)找到對(duì)應(yīng)的內(nèi)容,再填充到類對(duì)象中!

3.Initialization(初始化)

Initialization階段就是真正的對(duì)類對(duì)象進(jìn)行初始化(根據(jù)寫的代碼),尤其是針對(duì)靜態(tài)成員

4.典型的面試題

class A {
    public A(){
        System.out.println("A的構(gòu)造方法");
    }
    {
        System.out.println("A的構(gòu)造代碼塊");
    }
    static {
        System.out.println("A的靜態(tài)代碼塊");
    }}class B extends A{
    public B(){
        System.out.println("B的構(gòu)造方法");
    }
    {
        System.out.println("B的構(gòu)造代碼塊");
    }
    static {
        System.out.println("B的靜態(tài)代碼塊");
    }}public class Test extends B{
    public static void main(String[] args) {
        new Test();
        new Test();
    }}

可以自己先嘗試寫一下輸出的結(jié)果

做這樣的題就需要把握幾個(gè)大的原則:

  • 類加載階段就會(huì)進(jìn)行靜態(tài)代碼塊的執(zhí)行,要想創(chuàng)建實(shí)例,勢(shì)必要先進(jìn)行類加載

  • 靜態(tài)代碼塊只是類加載階段執(zhí)行一次,其他階段都不會(huì)再執(zhí)行

  • 構(gòu)造方法和構(gòu)造代碼塊每次實(shí)例化都會(huì)執(zhí)行,而且構(gòu)造代碼塊會(huì)在構(gòu)造方法前面執(zhí)行~~

  • 父類執(zhí)行在前,子類執(zhí)行在后!

  • 程序是從main開始執(zhí)行的,main的Test的方法,因此要執(zhí)行main就需要先加載Test類

  • 只有涉及到這個(gè)類了,類里面的東西才會(huì)被加載

輸出結(jié)果:
A的靜態(tài)代碼塊
B的靜態(tài)代碼塊
A的構(gòu)造代碼塊
A的構(gòu)造方法
B的構(gòu)造代碼塊
B的構(gòu)造方法
A的構(gòu)造代碼塊
A的構(gòu)造方法
B的構(gòu)造代碼塊
B的構(gòu)造方法

5.雙親委派模型

這個(gè)東西是類加載中的一個(gè)環(huán)節(jié),處于Loading階段(比較靠前的部分),雙親委派模型描述的就是JVM中的類加載器,如何根據(jù)類的全限定名(java.lang.String)找到.class文件的過程。這里的類加載器是JVM專門提供的對(duì)象,主要負(fù)責(zé)進(jìn)行類加載,所以找文件的過程也是由類加載器來(lái)負(fù)責(zé)的,.class文件可能放置的位置有很多,有的要放到JDK目錄里面,有的放到項(xiàng)目目錄里面,還有的在其他特定的位置里面,因此JVM提供了多個(gè)類加載器,每個(gè)類加載器負(fù)責(zé)一個(gè)片區(qū),而默認(rèn)的類加載器主要有3個(gè):

  • BootStrapClassLoader:負(fù)責(zé)加載標(biāo)準(zhǔn)庫(kù)中的類(String,ArrayList,Random,Scanner…)

  • ExtensionClassLoader:負(fù)責(zé)加載JDK擴(kuò)展的類(現(xiàn)在很少用到)

  • ApplicationClassLoader:負(fù)責(zé)加載當(dāng)前項(xiàng)目目錄中的類

  • 另外程序員還可以自定義類加載器,來(lái)加載其他目錄中的類,Tomcat就自定義了類加載器,用來(lái)專門加載webapps里面的.class

雙親委派模型就描述了這個(gè)找目錄的過程,也就是上述類加載器是如何配合的
考慮找一下java.lang.String:

  • 程序啟動(dòng),就會(huì)先進(jìn)入ApplicationClassLoader類加載器

  • ApplicationClassLoader類加載器就會(huì)檢查下,它的父加載器是否已經(jīng)加載過了,如果沒有,就調(diào)用父 類加載器ExtensionClassLoader

  • ExtensionClassLoader類加載器就會(huì)檢查下,它的父加載器是否已經(jīng)加載過了,如果沒有,就調(diào)用父 類加載器BootStrapClassLoader

  • BootStrapClassLoader類加載器也會(huì)檢查下,它的父加載器是否已經(jīng)加載過了,然后發(fā)現(xiàn)沒有父親,于是就掃描自己負(fù)責(zé)的目錄

  • 然后java.lang.String這個(gè)類就在標(biāo)準(zhǔn)庫(kù)中能找到,然后后續(xù)就由BootStrapClassLoader加載器負(fù)責(zé)后續(xù)的加載過程,查找環(huán)節(jié)就結(jié)束了!
    Java之JVM的知識(shí)點(diǎn)有哪些

考慮找一下自己寫的Test類:

  • 程序啟動(dòng),就會(huì)先進(jìn)入ApplicationClassLoader類加載器

  • ApplicationClassLoader類加載器就會(huì)檢查下,它的父加載器是否已經(jīng)加載過了,如果沒有,就調(diào)用父 類加載器ExtensionClassLoader

  • ExtensionClassLoader類加載器就會(huì)檢查下,它的父加載器是否已經(jīng)加載過了,如果沒有,就調(diào)用父 類加載器BootStrapClassLoader

  • BootStrapClassLoader類加載器也會(huì)檢查下,它的父加載器是否已經(jīng)加載過了,然后發(fā)現(xiàn)沒有父親,于是就掃描自己負(fù)責(zé)的目錄,沒掃描到,就會(huì)回到子加載器中繼續(xù)掃描

  • ExtensionClassLoader掃描自己負(fù)責(zé)的目錄,也沒有掃描到,再回到子加載器中繼續(xù)掃描

  • ApplicationClassLoader也掃描自己負(fù)責(zé)的目錄,自己寫的類就在自己的項(xiàng)目目錄下,因此就能找到,然后后續(xù)的類加載就由ApplicationClassLoad完成,此時(shí)查找目錄的環(huán)節(jié)就結(jié)束了~~(另外如果ApplicationClassLoader也沒有找到們就會(huì)拋出ClassNotFoundException異常)
    Java之JVM的知識(shí)點(diǎn)有哪些

這一套查找規(guī)則就稱為雙親委派模型,那為啥JVM要這樣設(shè)計(jì)呢,理由就是一旦程序員自己寫的類和全限定類名重復(fù)了,也能夠成功加載標(biāo)準(zhǔn)庫(kù)中的類,而不是自己寫的類!!!
另外如果是自定義的類加載器,要不要遵守這個(gè)雙親委派模型呢?
答案是可以遵守也可以不遵守,主要看需求,例如Tomcat加載webapp中的類,就沒有遵守,因?yàn)樽袷亓松厦娴念惣虞d器也是不可能找到的!

三.JVM的垃圾回收

JVM中的垃圾回收機(jī)制(GC),一般在寫代碼的時(shí)候,經(jīng)常就會(huì)涉及到申請(qǐng)內(nèi)存,例如創(chuàng)建一個(gè)變量,new一個(gè)對(duì)象,調(diào)用一個(gè)方法,加載類…而申請(qǐng)內(nèi)存的時(shí)機(jī)一般是明確的(需要保存某個(gè)或某些數(shù)據(jù)就需要申請(qǐng)內(nèi)存),但是釋放內(nèi)存的時(shí)機(jī),卻是不那么清楚的,釋放的早了也不行(如果還是要使用的,結(jié)果已經(jīng)被釋放了這就讓其無(wú)內(nèi)存可用了,就讓這些數(shù)據(jù)"無(wú)處可去"),釋放的晚了也不行(釋放晚了,大量的囤積很有可能讓可用內(nèi)存逐漸變少,很有可能會(huì)出現(xiàn)內(nèi)存泄漏問題,就是無(wú)內(nèi)存可以使用),因此內(nèi)存的釋放要恰到好處才好!
而垃圾回收的本職是靠運(yùn)行時(shí)環(huán)境額外做了很多的工作來(lái)完成釋放內(nèi)存操作的,這讓程序員的心智負(fù)擔(dān)大大降低了,但是垃圾回收也是有劣勢(shì)的:①消耗額外的開銷(消耗資源耕更多了);②可能會(huì)影響程序的流暢運(yùn)行(垃圾回收會(huì)經(jīng)常引入STW問題(Stop The World))

垃圾回收的內(nèi)存有哪些呢,是全部都要回收嘛?
當(dāng)然不是了,就用上面的四個(gè)區(qū)域來(lái)說一下:

  • 程序計(jì)數(shù)器:這個(gè)內(nèi)存是固定大小的,不涉及到釋放,也就不需要GC了;

  • 棧:當(dāng)函數(shù)調(diào)用完畢,對(duì)應(yīng)的棧幀也就自動(dòng)釋放了,也是不需要GC的;

  • 堆:這是最需要GC的內(nèi)存,一般代碼中的大量的內(nèi)存都在堆上;
    Java之JVM的知識(shí)點(diǎn)有哪些
    而這三個(gè)區(qū)域到底哪些是需要釋放的,對(duì)于這種一部分在使用,一部分不再使用的對(duì)象,整體來(lái)說就是不釋放的,只有等到這個(gè)對(duì)象完全不再使用,才真正的進(jìn)行釋放,因此在GC中就不會(huì)出現(xiàn)半個(gè)對(duì)象的情況,因此垃圾回收的基本單位就是對(duì)象,而不是字節(jié)!

  • 方法區(qū):類對(duì)象,類加載的,而只有進(jìn)行到類卸載的時(shí)候才需要進(jìn)行釋放內(nèi)存,而卸載操作是非常低頻的,因此幾乎就不涉及到GC!

下面就具體來(lái)看一下是怎么回收的:

1.找垃圾/判定垃圾

而當(dāng)下有兩個(gè)主流的方案:

1.1.基于引用計(jì)數(shù)

這不是Java中采取的方案,這是Python及其他語(yǔ)言的方案,因此這里就簡(jiǎn)單介紹一下,就不過多介紹了~
而引用計(jì)數(shù)的具體思路就是針對(duì)每個(gè)對(duì)象,都會(huì)額外引入一小塊內(nèi)存,來(lái)保存這個(gè)對(duì)象有多少個(gè)引用指向它
Java之JVM的知識(shí)點(diǎn)有哪些
而這樣的引用計(jì)數(shù)存在兩個(gè)缺陷:

  • 空間利用率比較低!!!,每個(gè)new的對(duì)象都需要搭配一個(gè)計(jì)數(shù)器,假設(shè)一個(gè)計(jì)數(shù)器4個(gè)字節(jié),如果對(duì)象本身比較大(幾百個(gè)字節(jié)),那么這個(gè)計(jì)數(shù)器就無(wú)所謂,而一旦這個(gè)對(duì)象本身就比較小(4個(gè)字節(jié)),那么再多出來(lái)4個(gè)字節(jié),就相當(dāng)于空間利用率就浪費(fèi)了一倍,因此空間利用率會(huì)比較低~

  • 有循環(huán)引用的問題
    Java之JVM的知識(shí)點(diǎn)有哪些
    因此使用引用計(jì)數(shù)也是會(huì)有大量的問題出現(xiàn)的,而想Python,PHP之類的語(yǔ)言也不是只使用引用計(jì)數(shù)器就完成GC的,也是配合了一些其他的機(jī)制來(lái)完成的!

1.2.基于可達(dá)性分析

可達(dá)性分析是Java所采取的方案,可達(dá)性分析是通過一些額外的線程,定期針對(duì)整個(gè)內(nèi)存空間的對(duì)象進(jìn)行掃描,有一些起始位置(GCRoots),然后就類似于深度優(yōu)先遍歷一樣(可以想象成是一棵樹),把可以訪問到的對(duì)象都標(biāo)記一邊(帶有標(biāo)記的對(duì)象就是可達(dá)的對(duì)象),而沒有被標(biāo)記的對(duì)象,就是不可達(dá)的對(duì)象,也就是垃圾,應(yīng)該被釋放掉!
這里的GCRoots(從這些位置開始遍歷):

  • 棧上的局部變量;

  • 常量池中的引用指向的對(duì)象;

  • 方法區(qū)中的靜態(tài)成員指向的對(duì)象;

因此可達(dá)性分析的優(yōu)點(diǎn)就是解決了引用計(jì)數(shù)的缺點(diǎn):空間利用率低,循環(huán)引用;而可達(dá)性分析的缺點(diǎn)也很明顯:系統(tǒng)開銷大,遍歷一次可能比較慢~

因此找垃圾也是很簡(jiǎn)單的,核心就是確認(rèn)這個(gè)對(duì)象未來(lái)是否還會(huì)使用,看還有沒有引用指向它,應(yīng)不應(yīng)該釋放掉!

2.釋放垃圾

既然已經(jīng)明確了什么是垃圾,接下來(lái)就要回收垃圾了,而回收垃圾有三種基本策略,下面來(lái)看一下!

2.1.標(biāo)記-請(qǐng)除

Java之JVM的知識(shí)點(diǎn)有哪些

這里的標(biāo)記就是可達(dá)性分析的過程,而清除就是釋放內(nèi)存,假設(shè)上面是一塊內(nèi)存,而打鉤的區(qū)域代表是垃圾,此時(shí)如果直接釋放掉,雖然內(nèi)存是還給系統(tǒng)了,但是釋放掉的內(nèi)存是離散的,不是連續(xù)的,而這樣帶來(lái)的問題就是"內(nèi)存碎片",空閑的內(nèi)存可能會(huì)有很多,假設(shè)加起來(lái)一共是1G,而此時(shí)想要申請(qǐng)500MB的空間,按理是可以申請(qǐng)到的,但在這里是有可能申請(qǐng)失敗的(因?yàn)橐暾?qǐng)的500MB是連續(xù)的內(nèi)存,每次申請(qǐng)的內(nèi)存都是連續(xù)的內(nèi)存空間,而這里的1G可能是多個(gè)碎片加起來(lái)的),因此這樣的問題其實(shí)是非常影響程序運(yùn)行的

2.2.復(fù)制算法

由于上面的標(biāo)記-清除策略可能會(huì)帶來(lái)內(nèi)存碎片的問題,因此引入了復(fù)制算法來(lái)解決這一問題
Java之JVM的知識(shí)點(diǎn)有哪些
上面是一塊內(nèi)存,復(fù)制算法的策略就是內(nèi)存使用一半,丟一半,不全部使用,在使用的一般里面把不是垃圾的拷貝到另一半(這個(gè)拷貝是JVM內(nèi)部處理好的,不用糾結(jié)),然后把前面使用的全部?jī)?nèi)存都釋放掉,這樣內(nèi)存碎片的問題就迎刃而解了!
所以復(fù)制算法就有兩個(gè)很大的問題:

  • 內(nèi)存空間利用率低(只使用了一般的內(nèi)存);

  • 如果要保留的對(duì)象多,要釋放的對(duì)象少,那么復(fù)制的開銷就很大;

2.3.標(biāo)記-整理

這又是針對(duì)復(fù)制算法,再進(jìn)一步做出改進(jìn)!
Java之JVM的知識(shí)點(diǎn)有哪些
標(biāo)記整理的策略就是將不是垃圾的內(nèi)存整理到一起,然后釋放掉后面的全部?jī)?nèi)存,就類似于順序表刪除中間元素的操作一樣,有一個(gè)搬運(yùn)的過程!
這個(gè)方案空間利用率是高了,但是仍然沒有辦法解決復(fù)制/搬運(yùn)元素開銷大的問題!

上述的三種方案,雖然能夠解決問題,但是都有各自的缺陷,因此實(shí)際上JVM中的實(shí)現(xiàn),會(huì)把多種方案結(jié)合起來(lái)使用,也就是"分代回收"!!!

2.4分代回收

這里的分代就是針對(duì)對(duì)象來(lái)進(jìn)行分類(根據(jù)對(duì)象的"年齡"進(jìn)行分類,而這里的年齡表示一個(gè)對(duì)象熬過一輪GC的掃描,就稱"長(zhǎng)了一歲"),而針對(duì)不同年齡的對(duì)象,就采取不同的方案!!!
Java之JVM的知識(shí)點(diǎn)有哪些
這就是整個(gè)分代回收的過程!

3.垃圾回收器

上面的找垃圾和釋放垃圾都只是算法的思想,并不是真正的落地實(shí)現(xiàn)的過程,而真正實(shí)現(xiàn)上述算法模塊的是"垃圾回收器",下面來(lái)介紹一些具體的垃圾回收器:

3.1.Serial收集器和Serial Old收集器

Serial收集器是給新生代提供的垃圾回收器,Serial Old收集器是給老年代提供的垃圾回收器,這兩個(gè)收集器是串行收集的,而且在進(jìn)行垃圾的掃描和釋放的時(shí)候,業(yè)務(wù)線程要停止工作,所以這樣的方式掃描的滿,釋放的也慢,而且也能產(chǎn)生嚴(yán)重的STW!

3.2.ParNew收集器,Parallel Scavenge收集器和Parallel Old收集器

ParNew收集器,Parallel Scavenge收集器都是提供給新生代的,Parallel Scavenge收集器比起ParNew收集器加了一些參數(shù),可以控制STW的時(shí)間,就是多了一些更強(qiáng)的功能,Parallel Old收集器是提供給老年代的,這三個(gè)收集器都是并行收集的,就是引入了多線程的方式來(lái)解決掃描垃圾和釋放垃圾的功能!

上面的這幾個(gè)回收器都是歷史遺留下來(lái)的,也就是比較老的垃圾回收方式,另外再介紹兩個(gè)更新的垃圾回收器!

3.3.CMS收集器

CMS收集器設(shè)計(jì)的比較巧妙,其設(shè)計(jì)的初衷是盡可能讓STW時(shí)間短,Java8使用的正是CMS收集器,下面簡(jiǎn)單介紹一下CMS收集器的過程:

  1. 初始標(biāo)記:速度很快,會(huì)引起短暫的STW(只是找到GCRoots);

  2. 并發(fā)標(biāo)記:速度很快,但是可以和業(yè)務(wù)線程并發(fā)執(zhí)行,不會(huì)產(chǎn)生STW;

  3. 重新標(biāo)記:在2業(yè)務(wù)代碼可能會(huì)影響并發(fā)標(biāo)記的結(jié)果(業(yè)務(wù)線程在執(zhí)行,就有可能產(chǎn)生新的垃圾),因此這一步就是針對(duì)2的結(jié)果進(jìn)行微調(diào),雖然會(huì)引起STW,但只是微調(diào),速度很快;
    上面三步都是基于可達(dá)性分析!

  4. 回收內(nèi)存:也是和業(yè)務(wù)線程并發(fā)執(zhí)行,不會(huì)產(chǎn)生STW,這是基于標(biāo)記整理;

3.4.G1收集器

G1收集器是唯一一款全區(qū)域的垃圾回收器,從Java11開始使用的就是G1收集器,這個(gè)收集器是把整個(gè)內(nèi)存,分成了很多小的區(qū)域Region,給這些Region進(jìn)行了不同的標(biāo)記,有的Region放新生代對(duì)象,有的Region放老年代對(duì)象,然后掃描的時(shí)候,就一次掃描若干個(gè)Region(不追求一輪GC就掃描完,需要分多次掃描),這樣對(duì)于業(yè)務(wù)代碼的影響也是最小的,

這兩個(gè)新的收集器的核心思想就是化整為零,G1當(dāng)下可以優(yōu)化到讓STW停頓時(shí)間小于1ms,這是完全可以接收的!上面就是關(guān)于JVM的一些學(xué)習(xí)了,這里的收集器主要還是了解為主,主要還是上面的垃圾回收思想很重要!!!

以上就是“Java之JVM的知識(shí)點(diǎn)有哪些”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會(huì)為大家更新不同的知識(shí),如果還想學(xué)習(xí)更多的知識(shí),請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(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)容。

AI