日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

十个问题弄清JVMGC(二)

發(fā)布時(shí)間:2024/9/3 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 十个问题弄清JVMGC(二) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
簡(jiǎn)介: 每個(gè)java開發(fā)同學(xué)不管是日常工作中還是面試?yán)?#xff0c;都會(huì)遇到JDK、JVM和GC的問(wèn)題。本文會(huì)從以下10個(gè)問(wèn)題為切入點(diǎn),帶著大家一起全面了解一下JVM的方方面面。

每個(gè)java開發(fā)同學(xué)不管是日常工作中還是面試?yán)?#xff0c;都會(huì)遇到JDK、JVM和GC的問(wèn)題。本文會(huì)從以下10個(gè)問(wèn)題為切入點(diǎn),帶著大家一起全面了解一下JVM的方方面面。

  • JVM、JRE和JDK的區(qū)別和聯(lián)系
  • JVM是什么?以及它的主要作用
  • JVM的核心功能有哪些
  • 類加載機(jī)制和過(guò)程
  • 運(yùn)行時(shí)數(shù)據(jù)區(qū)的邏輯結(jié)構(gòu)
  • JVM的內(nèi)存模型
  • 如何確定對(duì)象是垃圾
  • 垃圾收集的算法有哪些
  • 各種問(wèn)世的垃圾收集器
  • JVM調(diào)優(yōu)的參數(shù)配置
  • 上一篇文章結(jié)尾時(shí)我們談到,就JVM的設(shè)計(jì)規(guī)范,從使用用途角度JVM的內(nèi)存大體的分為:線程私有內(nèi)存區(qū) 和 線程共享內(nèi)存區(qū)。

    線程私有內(nèi)存區(qū)在類加載器編譯某個(gè)class文件時(shí)就確定了執(zhí)行時(shí)需要的“程序計(jì)數(shù)器”和“虛擬棧幀”等所需的空間,并且會(huì)伴隨著當(dāng)前執(zhí)行線程的產(chǎn)生而產(chǎn)生,執(zhí)行線程的消亡而消亡,因此“線程私有內(nèi)存區(qū)”并不需要考慮內(nèi)存管理和垃圾回收的問(wèn)題。線程共享內(nèi)存區(qū)在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建,被所有線程共享,是Java虛擬機(jī)所管理內(nèi)存中最應(yīng)該關(guān)注的和最大的一塊。首先我們來(lái)一起看一下“線程共享內(nèi)存區(qū)”的內(nèi)存模型是什么樣的?

    6、JVM的內(nèi)存模型

    如圖所示,JVM的內(nèi)存結(jié)構(gòu)分為堆和非堆兩大塊區(qū)域。

    • 其中“非堆”就是上篇文章我們提到的方法區(qū)或叫元數(shù)據(jù)區(qū),用來(lái)存儲(chǔ)class類信息的。
    • 而“堆”是用來(lái)存儲(chǔ)JVM各線程執(zhí)行期間所創(chuàng)建的實(shí)例對(duì)象或數(shù)組的。堆區(qū)分為兩大塊,一個(gè)是Old區(qū),一個(gè)是Young區(qū)。Young區(qū)分為兩大塊,一個(gè)是Survivor區(qū)(S0+S1),一塊是Eden區(qū)S0和S1一樣大,也可以叫From和To。

    之所以這樣劃分,設(shè)計(jì)者的目的無(wú)非就是為了內(nèi)存管理,也就是我們說(shuō)的垃圾回收。那么什么樣的對(duì)象是垃圾?垃圾回收算法有哪些?目前常用的垃圾回收器又有哪些?這篇文章我們一起弄清楚這些問(wèn)題和知識(shí)點(diǎn)。

    7、如何確定一個(gè)對(duì)象是垃圾?

    要想進(jìn)行垃圾回收,得先知道什么樣的對(duì)象是垃圾。目前確認(rèn)對(duì)象是否為垃圾的算法主要有兩種:引用計(jì)數(shù)法和可達(dá)性分析法。

    • 1、引用計(jì)數(shù)法:在對(duì)象中添加了一個(gè)引用計(jì)數(shù)器,當(dāng)有地方引用這個(gè)對(duì)象時(shí),引用計(jì)數(shù)器的值就加1,當(dāng)引用失效的時(shí)候,引用計(jì)數(shù)器的值就減1。當(dāng)引用計(jì)數(shù)器的值為0時(shí),JVM就開始回收這個(gè)對(duì)象。

    對(duì)于某個(gè)對(duì)象而言,只要應(yīng)用程序中持有該對(duì)象的引用,就說(shuō)明該對(duì)象不是垃圾,如果一個(gè)對(duì)象沒(méi)有任何指針對(duì)其引用,它就是垃圾。這種方法雖然很簡(jiǎn)單、高效,但是JVM一般不會(huì)選擇這個(gè)方法,因?yàn)檫@個(gè)方法會(huì)出現(xiàn)一個(gè)弊端:當(dāng)對(duì)象之間相互指向時(shí),兩個(gè)對(duì)象的引用計(jì)數(shù)器的值都會(huì)加1,而由于兩個(gè)對(duì)象時(shí)相互指向,所以引用不會(huì)失效,這樣JVM就無(wú)法回收。

    • 2、可達(dá)性分析法:針對(duì)引用計(jì)數(shù)算法的弊端,JVM采用了另一種算法,以一些"GC Roots"的對(duì)象作為起始點(diǎn)向下搜索,搜索所走過(guò)的路徑稱為引用鏈(Reference Chain),當(dāng)一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈相連時(shí),則證明此對(duì)象是不可用的,即可以進(jìn)行垃圾回收。否則,證明這個(gè)對(duì)象有用,不是垃圾。


    上圖中的obj7和obj8雖然它們互相引用,但從GC Roots出發(fā)這兩個(gè)對(duì)象不可達(dá),所以會(huì)被標(biāo)記為垃圾。JVM會(huì)把以下幾類對(duì)象作為GC Roots:

    • (1) 虛擬機(jī)棧(棧幀中本地變量表)中引用的對(duì)象;
    • (2) 方法區(qū)中類靜態(tài)屬性引用的對(duì)象;
    • (3) 方法區(qū)中常量引用的對(duì)象;
    • (4) 本地方法棧中JNI(Native方法)引用的對(duì)象。

    注:在可達(dá)性分析算法中不可達(dá)的對(duì)象,并不是直接被回收,這時(shí)它們處于緩刑狀態(tài),至少需要進(jìn)行兩次標(biāo)記才會(huì)確定該對(duì)象是否被回收:

    第一次標(biāo)記:如果對(duì)象在進(jìn)行可達(dá)性分析后發(fā)現(xiàn)沒(méi)有與GC Roots相連接的引用鏈,那它將會(huì)被第一次標(biāo)記;

    第二次標(biāo)記:第一次標(biāo)記后接著會(huì)進(jìn)行一次篩選,篩選的條件是此對(duì)象是否有必要執(zhí)行finalize()方法(該方法可將此對(duì)象與GC Roots建立聯(lián)系)。在finalize()方法中沒(méi)有重新與引用鏈建立關(guān)聯(lián)關(guān)系的,將被進(jìn)行第二次標(biāo)記。

    第二次標(biāo)記成功的對(duì)象將真的會(huì)被回收,如果對(duì)象在finalize()方法中重新與引用鏈建立了關(guān)聯(lián)關(guān)系,那么將會(huì)逃離本次回收,繼續(xù)存活。

    8、垃圾收集的算法有哪些

    知道了如何JVM確定哪些對(duì)象是垃圾后,下面我們來(lái)看一下,面對(duì)這些垃圾對(duì)象,JVM的回收算法都有哪些。

    1、 標(biāo)記-清除算法(Mark-Sweep)

    • 第一步“標(biāo)記”,如下圖所示把堆里所有的對(duì)象都掃描一遍,找出哪些是垃圾需要回收的對(duì)象,并且把它們標(biāo)記出來(lái)。

    • 第二步“清除”,把第一步標(biāo)記為“UnReference Object”(無(wú)引用或不可達(dá))的對(duì)象清除掉,釋放內(nèi)存空間。

    這種算法的缺點(diǎn)主要有兩點(diǎn):

    (1) 標(biāo)記和清除兩個(gè)過(guò)程都比較耗時(shí),效率不高

    (2) 清除后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片空間,碎片空間太多可能會(huì)導(dǎo)致當(dāng)程序后續(xù)需要?jiǎng)?chuàng)建較大對(duì)象時(shí),無(wú)法找到足夠連續(xù)的內(nèi)存空間而不得不再次觸發(fā)垃圾回收。

    2、 標(biāo)記-復(fù)制算法(Mark-Copying)

    將內(nèi)存劃分為兩塊區(qū)域,每次使用其中一塊,當(dāng)其中一塊用滿,觸發(fā)垃圾回收的時(shí)候,將存活的對(duì)象復(fù)制到另一塊上去,然后把之前使用的那一塊進(jìn)行格式化,一次性清除干凈。

    (清除前)

    (清除后)

    “標(biāo)記-復(fù)制”算法的缺點(diǎn)顯而易見,就是內(nèi)存空間利用率低。

    3、 標(biāo)記-整理算法(Mark-Compact)

    標(biāo)記整理算法標(biāo)記過(guò)程仍然與"標(biāo)記-清除"算法一樣,但是后續(xù)步驟不是直接對(duì)可回收對(duì)象進(jìn)行清理,而是讓所有存活的對(duì)象都向一端移動(dòng),然后直接清理掉端邊界以外的內(nèi)存。

    將所有存活的對(duì)象向一邊移動(dòng),清理掉存活邊界以外的全部?jī)?nèi)存空間。

    結(jié)合這三種算法我們可以看到,

    • “標(biāo)記-復(fù)制”算法的優(yōu)點(diǎn)是回收效率高,但空間利用率上有一定的浪費(fèi)。
    • 而“標(biāo)記-整理”算法由于需要向一側(cè)移動(dòng)等一系列操作,其效率相對(duì)低一些,但對(duì)內(nèi)存空間管理上十分優(yōu)異。
    • 因此,“標(biāo)記-復(fù)制”算法適用于那些生命周期短、回收頻率高的內(nèi)存對(duì)象,
    • 而標(biāo)記-整理”算法適用于那些生命周期長(zhǎng)、回收頻率低,但注重回收一次內(nèi)存空間得到足夠釋放的場(chǎng)景。

    因此JVM的設(shè)計(jì)者將JVM的堆內(nèi)存,分為了兩大塊區(qū)域Young區(qū)和Old區(qū),Young區(qū)存儲(chǔ)的就是那些生命周期短,使用一兩次就不再使用的對(duì)象,回收一次基本上該區(qū)域十之有八的對(duì)象全部被回收清理掉,因此Young區(qū)采用的垃圾回收算法也就是“標(biāo)記-復(fù)制”算法。Old區(qū)存儲(chǔ)的是那些生命周期長(zhǎng),經(jīng)過(guò)多次回收后仍然存活的對(duì)象,就把它們放到Old區(qū)中,平時(shí)不再去判斷這些對(duì)象的可達(dá)性,直到Old區(qū)不夠用為止,再進(jìn)行一次統(tǒng)一的回收,釋放出足夠的連續(xù)的內(nèi)存空間。

    9、各種問(wèn)世的垃圾收集器

    鑒于Young區(qū)和Old區(qū)需要采用不同的垃圾回收算法,因此在JVM的整個(gè)垃圾收集器的演進(jìn)各個(gè)時(shí)代里,針對(duì)Young區(qū)和Old區(qū)每個(gè)時(shí)代都是不同的垃圾收集機(jī)制。從JDK1.3開始到目前,JVM垃圾收集器的演進(jìn)大體分為四個(gè)時(shí)代:串行時(shí)代、并行時(shí)代、并發(fā)時(shí)代和G1時(shí)代。

    1、串行時(shí)代:Serial(Young區(qū))+ Serial Old(Old區(qū))

    JDK3(1.3)的時(shí)候,大概是2000年左右,那個(gè)時(shí)代基本計(jì)算機(jī)都是單核一個(gè)CPU的,因此垃圾回收最初的設(shè)計(jì)實(shí)現(xiàn)也是基于單核單線程工作的。并且垃圾回收線程的執(zhí)行相對(duì)于正常業(yè)務(wù)線程執(zhí)行來(lái)說(shuō)還是STW(stop the world)的,使用一個(gè)CPU或者一條收集線程去完成垃圾收集工作,這個(gè)線程執(zhí)行的時(shí)候其它線程需要停止。

    串行收集器采用單線程stop-the-world的方式進(jìn)行收集。當(dāng)內(nèi)存不足時(shí),串行GC設(shè)置停頓標(biāo)識(shí),待所有線程都進(jìn)入安全點(diǎn)(Safepoint)時(shí),應(yīng)用線程暫停,串行GC開始工作,采用單線程方式回收空間并整理內(nèi)存。單線程也意味著復(fù)雜度更低、占用內(nèi)存更少,但同時(shí)也意味著不能有效利用多核優(yōu)勢(shì)。因此,串行收集器特別適合堆內(nèi)存不高、單核甚至雙核CPU的場(chǎng)合。

    2、并行時(shí)代:Parallel Scavenge(Young區(qū)) + Parallel Old(Old區(qū))

    并行收集器是以關(guān)注吞吐量為目標(biāo)的垃圾收集器,也是server模式下的默認(rèn)收集器配置,對(duì)吞吐量的關(guān)注主要體現(xiàn)在年輕代Parallel Scavenge收集器上。

    并行收集器與串行收集器工作模式相似,都是stop-the-world方式,只是暫停時(shí)并行地進(jìn)行垃圾收集。年輕代采用復(fù)制算法,老年代采用標(biāo)記-整理,在回收的同時(shí)還會(huì)對(duì)內(nèi)存進(jìn)行壓縮。關(guān)注吞吐量主要指年輕代的Parallel Scavenge收集器,通過(guò)兩個(gè)目標(biāo)參數(shù)-XX:MaxGCPauseMills和-XX:GCTimeRatio,調(diào)整新生代空間大小,來(lái)降低GC觸發(fā)的頻率。并行收集器適合對(duì)吞吐量要求遠(yuǎn)遠(yuǎn)高于延遲要求的場(chǎng)景,并且在滿足最差延時(shí)的情況下,并行收集器將提供最佳的吞吐量。

    3、 并發(fā)時(shí)代:CMS(Old區(qū))

    并發(fā)標(biāo)記清除(CMS)是以關(guān)注延遲為目標(biāo)、十分優(yōu)秀的垃圾回收算法,CMS是針對(duì)Old區(qū)的垃圾回收實(shí)現(xiàn)。

    老年代CMS每個(gè)收集周期都要經(jīng)歷:初始標(biāo)記、并發(fā)標(biāo)記、重新標(biāo)記、并發(fā)清除。其中,初始標(biāo)記以STW的方式標(biāo)記所有的根對(duì)象;并發(fā)標(biāo)記則同應(yīng)用線程一起并行,標(biāo)記出根對(duì)象的可達(dá)路徑;在進(jìn)行垃圾回收前,CMS再以一個(gè)STW進(jìn)行重新標(biāo)記,標(biāo)記那些由mutator線程(指引起數(shù)據(jù)變化的線程,即應(yīng)用線程)修改而可能錯(cuò)過(guò)的可達(dá)對(duì)象;最后得到的不可達(dá)對(duì)象將在并發(fā)清除階段進(jìn)行回收。值得注意的是,初始標(biāo)記和重新標(biāo)記都已優(yōu)化為多線程執(zhí)行。CMS非常適合堆內(nèi)存大、CPU核數(shù)多的服務(wù)器端應(yīng)用,也是G1出現(xiàn)之前大型應(yīng)用的首選收集器。

    - 但CMS有以下兩個(gè)缺陷:

    • (1)由于它是標(biāo)記-清除不是標(biāo)記-整理,因此會(huì)產(chǎn)生內(nèi)存碎片,Old區(qū)會(huì)隨著時(shí)間的推移而終究被耗盡或產(chǎn)生無(wú)法分配大對(duì)象的情況。最后不得不通過(guò)底層的擔(dān)保機(jī)制(CMS背后有串行的回收作為兜底)進(jìn)行一次Full GC,并進(jìn)行內(nèi)存壓縮。
    • (2)由于標(biāo)記和清除都是通應(yīng)用線程并發(fā)進(jìn)行,兩類線程同時(shí)執(zhí)行時(shí)會(huì)增加堆內(nèi)存的占用,一旦某一時(shí)刻內(nèi)存不夠用,就會(huì)觸發(fā)底層擔(dān)保機(jī)制,又采用串行回收進(jìn)行一次STW的垃圾回收。

    4、G1時(shí)代:Garbage First

    G1收集器時(shí)代,Java堆的內(nèi)存布局與就與其他收集器有很大差別,它將整個(gè)Java堆劃分為多個(gè)大小相等的獨(dú)立區(qū)域(Region),雖然還保留有新生代和老年代的概念,但新生代和老年代不再是物理隔離的了,它們都是一部分Region(不需要連續(xù))的集合。

    如上圖所示,每一個(gè)Region(分區(qū))大小都是一樣的,1~32M之間的數(shù)值,但必須是2的指數(shù)。設(shè)置Region大小通過(guò)以下參數(shù):-XX:G1HeapRegionSize=M。
    G1收集器的原理或特點(diǎn)主要有以下三點(diǎn):

    (1)內(nèi)存邏輯上仍保留的分代的概念,每一個(gè)Region同一時(shí)間要么被標(biāo)記為新生代,要么被標(biāo)記為老年代,要么處于空閑;

    (2)整體上采用了“標(biāo)記-整理算法”,不會(huì)產(chǎn)生內(nèi)存碎片

    (3)可預(yù)測(cè)的停頓,G1整體采用的策略是“篩選回收”,也就是回收前會(huì)對(duì)各個(gè)待回收的Region的回收價(jià)值和成本進(jìn)行排序,根據(jù)G1配置所期望的回收時(shí)間,選擇排在前面的幾個(gè)Region進(jìn)行回收。

    其實(shí)之所以叫G1(Garbage First)就是因?yàn)樗鼉?yōu)先選擇回收垃圾比較多的Region分區(qū)。
    整體G1的垃圾回收工作步驟分為:初始標(biāo)記、并發(fā)標(biāo)記、最終標(biāo)記和篩選回收。

    5、ZGC:Zero GC

    這篇文章簡(jiǎn)單提一下這個(gè)最新問(wèn)世的垃圾收集器,之所以叫“Zero GC”是因?yàn)樗非蟮氖歉偷腉C停頓時(shí)間,追求的目標(biāo)是:支持TB級(jí)堆內(nèi)存(最大4T)、最大GC停頓10ms。JDK11新引入的ZGC收集器,不管是物理上還是邏輯上,ZGC中已經(jīng)不存在新老年代的概念了會(huì)分為一個(gè)個(gè)page,當(dāng)進(jìn)行GC操作時(shí)會(huì)對(duì)page進(jìn)行壓縮,因此沒(méi)有碎片問(wèn)題。由于其是JDK11和只能在64位的linux上使用,因此目前用得還比較少。

    結(jié)語(yǔ)

    以上總體兩篇文章七千字,就是我從JVM的作用、設(shè)計(jì)框架到JVM內(nèi)存管理的整體的體系化理解。感謝。

    拓展閱讀:十個(gè)問(wèn)題弄清JVM&GC(二)

    作者:宜信技術(shù)學(xué)院 譚文濤

    原文鏈接:https://developer.aliyun.com/article/770672?

    版權(quán)聲明:本文內(nèi)容由阿里云實(shí)名注冊(cè)用戶自發(fā)貢獻(xiàn),版權(quán)歸原作者所有,阿里云開發(fā)者社區(qū)不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。具體規(guī)則請(qǐng)查看《阿里云開發(fā)者社區(qū)用戶服務(wù)協(xié)議》和《阿里云開發(fā)者社區(qū)知識(shí)產(chǎn)權(quán)保護(hù)指引》。如果您發(fā)現(xiàn)本社區(qū)中有涉嫌抄襲的內(nèi)容,填寫侵權(quán)投訴表單進(jìn)行舉報(bào),一經(jīng)查實(shí),本社區(qū)將立刻刪除涉嫌侵權(quán)內(nèi)容。

    總結(jié)

    以上是生活随笔為你收集整理的十个问题弄清JVMGC(二)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。