<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Java GC 總結(jié),建議收藏

          共 12775字,需瀏覽 26分鐘

           ·

          2022-06-09 16:03

          • 垃圾標記算法
          • 垃圾回收算法
          • major gc、minor gc、full gc、mixed gc 又是什么,怎么觸發(fā)的
          • 垃圾回收器的介紹
          • Safe Point 和 Safe Region
          • 什么是 TLAB 和 PLAB ?
          • CMS、G1 新生代的 GC 如何避免全堆掃描
          • CMS 和 G1 為了防止并發(fā)時的漏標分別用了什么手段
          • 什么是 logging write barrier
          • CMS 常見問題
          • GC 事件和日志分析
          • JVM 常用參數(shù)匯總 關(guān)注公眾號,一起交流:潛行前行

          1 垃圾標記算法

          引用計算法

          • 引用計數(shù)法是最簡單有效的垃圾標記方法,它會把對象被引用的次數(shù)記錄下來,當(dāng)被引用時,計數(shù)加一。當(dāng)其他變量不再指向目標對象時,則引用減一。對象引用數(shù)為零時 ,則可以進行內(nèi)存回收釋放
          • 無法解決循環(huán)引用問題

          根可達性分析

          • 從 GC Root 開始進行對象搜索,可以被搜索到的對象即為可達對象,不可達對象便可以作為垃圾被回收掉。目前 Java 中主流的虛擬機均采用此算法
          • 在Java語言里,可作為GC Roots的對象包括下面幾種:
            • 虛擬機棧(棧幀中的本地變量表)中的引用的對象
            • 方法區(qū)中的類靜態(tài)屬性引用的對象
            • 方法區(qū)中的常量引用的對象
            • 本地方法棧中JNI(即一般說的Native方法)的引用的對象

          2 垃圾回收算法

          • 復(fù)制:將一塊內(nèi)存區(qū)域進行對半分,當(dāng)一半的內(nèi)存使用完時,便將其中存活的對象復(fù)制到另一半內(nèi)存區(qū)域中,原先的區(qū)域進行回收。不存在內(nèi)存碎片問題,實現(xiàn)簡單運行高效,但是有個缺點,就是對內(nèi)存的利用率只有 50%
          • 標記清除:算法分為 “標記” 和 “清理”兩個階段
            • 標記階段:標記出所有需要回收的對象
            • 清除階段:標記完成后,統(tǒng)一清除回收被標記的對象
            • 由于對象之前在內(nèi)存中的分布是無規(guī)律的,標記清除算法會產(chǎn)生大量不連續(xù)的內(nèi)存碎片,造成連續(xù)的大內(nèi)存空間缺失,阻礙大內(nèi)存對象的分配,嚴重時會觸發(fā)垃圾回收,甚至出現(xiàn) OutOfMemeryError。而且如果大部分的對象是朝生夕死的,標記的對象就會更多,效率更低
          • 標記整理:步驟與 標記清除步 驟一致,但它的第二步是整理標記之外的所有對象,將所有對象向前移動,之后直接回收掉存活對象之外的內(nèi)存區(qū)域。標記整理 不會存在內(nèi)存碎片,但是效率是偏低的

          按年代劃分-分代算法

          • 新生代回收(Minor GC/Young GC):指只是進行新生代的回收
          • 老年代回收(Major GC/Old GC):指只是進行老年代的回收。目前只有 CMS 垃圾回收器會有這個單獨的回收老年代的行為
          • 整堆回收(Full GC):收集整個堆,包括年輕代、老年代,如果有永久代的話還包括永久代

          3 major gc、minor gc、mixed gc又是什么,怎么觸發(fā)的?

          • major gc:個人理解應(yīng)該是指 old gc。不過有些人認為和 full gc 等價
            • 執(zhí)行 System.gc()、jmap -dump 等命令會觸發(fā) full gc
            • 有永久代的話,永久代滿了也會觸發(fā) full gc
            • 大對象直接在老年代申請分配,如果此時老年代空間不足則會觸發(fā) full gc
            • 新生代對象 gc 年齡到達閾值需要晉升,老年代如果放不下的話會觸發(fā) full gc
          • minor gc:指的也是年輕代的 young gc
            • 年輕代的 eden 快要被占滿的時候會觸發(fā) young gc
            • eden 快滿的觸發(fā)因素有兩個,一個是為對象分配內(nèi)存不夠,一個是為 TLAB 分配內(nèi)存不夠
          • mixed gc:這個是 G1 收集器特有的,指的是收集整個年輕代和部分老年代的 GC
            • 在 young gc 之后,當(dāng)老年代的堆占有率達到參數(shù) (-XX:InitiatingHeapOccupancyPercent) 設(shè)定的值時則觸發(fā) mixed GC

          4 垃圾回收器的介紹

          Serial New 和 Serial Old

          • jvm 誕生初期所采用的垃圾回收器,單線程,獨占式,適合單 CPU
          • 單線程進行垃圾回收時,必須暫停所有的工作線程,直到它回收結(jié)束。這個暫停稱之為 Stop The World ,但是 STW 會帶來差的性能影響

          Parallel Scavenge ?和 Parallel Old

          • 為了提高 jvm 的回收效率,jvm 使用了多線程的垃圾回收器,關(guān)注吞吐量的垃圾回收器,可以更高效的利用CPU 時間,從而盡快完成程序的運算任務(wù)
          • Parallel Scavenge 收集器提供了兩個參數(shù)用于精確控制吞吐量,可以分別是控制最大垃圾收集停頓時間
            • -XX:MaxGCPauseMillis參數(shù)以及直接設(shè)置吞吐量大小的
            • -XX:GCTimeRatio參數(shù)。其也經(jīng)常被稱為“吞吐量優(yōu)先”收集器

          ParNew 和 CMS

          • ParNew 與 Parallel Scavenge 差不多。區(qū)別是 Parallel Scavenge 是一個可控制的吞吐量并行垃圾回收器,ParNew 沒有參數(shù)來控制吞吐量和停頓時間
          • ParNew 可以和 CMS 搭配使用,而 Parallel Scavenge 不可用,其根本原因是設(shè)計上就是沒想過兼容 CMS
          • CMS(Concurrent Mark Sweep) 是一款針對老年代的垃圾回收器,追求最短的回收停頓時間(STW)為目標,采用的是 標記-清除 算法

          CMS 的回收流程

          • 初始標記:只標記與 GC Root 有直接關(guān)聯(lián)的對象,這類的對象比較少,標記快。需要 STW
          • 并發(fā)標記:并發(fā)標記與初始化標記的對象有關(guān)聯(lián)的所有對象,這類的對象比較多所以采用的并發(fā),與用戶線程一起跑
          • **并發(fā)預(yù)清理(Concurrent Preclean)**:并發(fā)標記階段是與應(yīng)用線程并發(fā)執(zhí)行的,有些引用關(guān)系已經(jīng)發(fā)生改變,通過卡片標記(Card Marking),如果引用關(guān)系發(fā)生改變,JVM會將發(fā)生改變的區(qū)域標記位“臟區(qū)”(Dirty Card),然后在本階段,這些臟區(qū)會被找出來,刷新引用關(guān)系,清除“臟區(qū)”標記
          • **并發(fā)可取消的預(yù)清理(Concurrent Abortable Preclean)**:和并發(fā)預(yù)清理階段工作差不多,用來減少Final Remark 階段的暫停時間。該階段會不斷循環(huán)處理:標記老年代的可達對象、掃描處理Dirty Card區(qū)域中的對象引用關(guān)系。循環(huán)中斷條件
            • 達到循環(huán)次數(shù)
            • 達到循環(huán)執(zhí)行時間閾值
            • 新生代內(nèi)存使用率達到閾值
          • 最終標記 (Final Remark):修正并發(fā)標記時候標記產(chǎn)生異動的對象標記,這塊的時間比初始標記稍長一些,但是比起并發(fā)標記要快很多。需要 STW
            • 遍歷新生代對象,重新標記
            • 根據(jù)GC Roots,重新標記
            • 遍歷老年代的Dirty Card,重新標記
          • 并發(fā)清除(Concurrent Sweep):與用戶線程一起運行,進行對象回收清除
          • 缺點
            • 浮動垃圾:在CMS進行并發(fā)清除階段,GC線程是并發(fā)的,所以在清除的時候用戶線程會產(chǎn)出新的垃圾。因此在進行回收時需要預(yù)留一部分的空間來存放這些新產(chǎn)生垃圾(JDK 1.6 設(shè)置的閾值為92%)。但是如果用戶線程產(chǎn)出的垃圾比較快,預(yù)留內(nèi)存放不下的時候就會出現(xiàn) Concurrent Mode Failure,這時虛擬機將臨時啟用 Serial Old 來替代 CMS。
            • 內(nèi)存碎片:因為采用的是 標記-清除 算法,會產(chǎn)生內(nèi)存碎片

          G1

          • G1 垃圾回收器的設(shè)計思想與上面的垃圾回收器的都不一樣,前面垃圾回收器采用的都是 分代劃分 的方式進行設(shè)計的,而 G1 則是將堆看作是一個整體的區(qū)域,這個區(qū)域被劃分成了一個個大小一致的獨立區(qū)域(Region),而每個區(qū)域都可以根據(jù)需要成為 Eden、Survivor 以及老年代區(qū)域

          G1的回收流程

          image.png
          • 初始標記(Initial Marking):標記與 GC Roots 能關(guān)聯(lián)到的對象,修改 TAMS (Top at Mark Start) 給堆對象拍個快照,這個過程是需要暫停用戶線程的,但是耗時非常的短。需要 STW

            image.png
            • Region 記錄著兩個 top-at-mark-start (TAMS) 指針,分別為?prevTAMS?和?nextTAMS。在 nextTAMS~top的之間對象是新分配的,被視為隱式 marked(存活對象)。對象是否存活使用 bitmap 位圖標志,prevBitmap 記錄第 n-1 輪 concurrent marking 所得的對象存活狀態(tài),nextBitmap 記錄第 n 輪 concurrent marking 的結(jié)果
            • top 是該 Region 的當(dāng)前分配指針,[bottom, top) 是當(dāng)前該 Region 已用的部分,[top, end) 是尚未使用的可分配空間
            • [bottom, prevTAMS):這部分里的對象存活信息可以通過?prevBitmap?來得知
            • [prevTAMS, nextTAMS):這部分里的對象在第 n-1 輪 concurrent marking 是隱式存活的
            • [nextTAMS, top):這部分里的對象在第 n 輪 concurrent marking 是隱式存活的
          • 并發(fā)標記(Concurrent Marking):進行掃描標記所有可回收的對象。當(dāng)掃描完成后,并發(fā)會有引用變化的對象,而這些對象會漏標這些漏標的對象會被 SATB 算法所解決

            • SATB(snapshot-at-the-beginning):舊對象區(qū)域 [bottom, nextTAMS) ?按 nextTAMS 生成時的存活快照為準,即對象在 nextTAMS 生成之后變成垃圾也不會被回收
            • 如果在并發(fā)標記時,引用發(fā)生改變的對象將被放入 satb_mark_queue 隊列(寫屏障實現(xiàn)),之后在最終標記階段,以隊列對象為根重新標記可能漏標的對象 (按快照的存活關(guān)系處理)
            • 新分配對象區(qū)域 [nextTAMS, top) 可能存在浮動垃圾,將在下次被收集
          • 最終標記 (Final Marking):暫停所有的用戶線程,對之前漏標的對象進行一個標記。需要 STW

          • 篩選回收( Live Data Counting and Evacuation):更新Region的統(tǒng)計數(shù)據(jù),對各個 Region 的回收價值進行一個排序,根據(jù)用戶所設(shè)置的停頓時間制定一個回收計劃,自由選擇任意個 Region 進行回收。將需要回收的Region 復(fù)制到空的 Region 區(qū)域中,再清除掉原來的整個Region區(qū)域。這塊還涉及到對象的移動所以需要暫停所有的用戶線程,多條回收器線程并行完成。需要 STW

            • 為什么需要 Stop The World呢?因為在篩選回收階段首先會對各個Region的回收價值和成本進行排序,根據(jù)用戶所期望的GC停頓時間(可以用JVM參數(shù) -XX:MaxGCPauseMillis 指定)來制定回收計劃,可以自由選擇任意多個Region構(gòu)成回收集,然后把決定回收的那一部分Region的存活對象復(fù)制到空的Region中,再清理掉整個舊Region的全部空間
            • 其實也可以做到與用戶程序一起并發(fā)執(zhí)行,但是停頓用戶線程將大幅提高收集效率

          G1 與 CMS 的區(qū)別

          • G1 從整體來看是基于 “標記—整理” 算法實現(xiàn)的收集器,從局部(兩個 Region 之間)上來看是基于“復(fù)制”算法實現(xiàn)的,這意味著 G1 運作期間不會產(chǎn)生內(nèi)存空間碎片,收集后能提供規(guī)整的可用內(nèi)存
          • G1 SATB 利用 write barrier 將所有即將被刪除的引用關(guān)系的舊引用記錄下來,最后以這些舊引用為根 Stop The World 地重新掃描一遍即可避免漏標問題。因此 G1 Final Marking 階段 Stop The World 與 CMS 的 remark 有一個本質(zhì)上的區(qū)別,那就是這個暫停只需要掃描以 write barrier 所追蹤到對象為根的對象, 而 CMS 的 remark 需要重新掃描整個根集合(產(chǎn)生新的根對象指向引用,需要掃描整個根集合),因而 CMS remark 有可能會非常慢

          G1 中的三種垃圾回收模式

          • YoungGC 觸發(fā)條件:young eden 區(qū)不夠用
          • Mixed GC 觸發(fā)條件
            • 在 YoungGC 之后,會觸發(fā) Concurrent Marking 并發(fā)階段,接著進行 mixed GC,mixed GC 主要工作就是回收并發(fā)標記過程中篩選出來的 Region 。和 ?young GC 流程基本一致
          • Full GC 觸發(fā)條件
            • mixed GC 趕不上內(nèi)存分配的速度,只能通過 full GC 來釋放內(nèi)存,這種情況解決方案后面再說
            • metaSpace 不足,對于大量使用反射,動態(tài)代理的類,由于動態(tài)代理的每個類都會生成一個新的類,同時class信息會存放在元空間,因此如果元空間不足, G1 會靠 full GC 來擴容元空間,這種情況解決方案就是擴大初始元空間大小
            • humongous 分配失敗, G1 分配大對象時,會靠 concurrent marking 或 full GC 回收空間,因此如果大對象分配失敗,則可能會引發(fā) full GC

          G1調(diào)優(yōu)參數(shù)

          • 開啟參數(shù):-XX:+UseG1GC
          • 最大GC暫停時間: -XX:MaxGCPauseMillis
          • 不要設(shè)置年輕代大小:不要使用-Xmn,因為 G1 是通過需要擴展或縮小年輕代大小,如果設(shè)置了年輕代大小,則會導(dǎo)致 G1 無法使用暫停時間目標

          5 Safe Point 和 Safe Region

          • jvm 準備進行 GC 階段,并不是隨時都能開始的,需要用戶線程進入一個安全的狀態(tài),才能開始 GC 操作。這個狀態(tài) 被稱為 safe point,在代碼上特定的位置點有下面幾種
            • 方法返回之前
            • 調(diào)用某個方法之后
            • 拋出異常位置
            • 循環(huán)的末尾
          • 用戶線程執(zhí)行到安全點時,會輪詢 GC 中斷標志,一旦出現(xiàn)則在安全點主動掛起線程
          • safe point 解決了用戶線程停頓,讓 jvm 進入GC。但如果用戶線程本身就處于 sleep 和 wait 狀態(tài)呢,線程不執(zhí)行,也達到了不了 safe point 位置。Safe Region 可以解決類似問題,Safe Region 是指在一段代碼片段中,引用關(guān)系不會發(fā)生變化。在這個區(qū)域內(nèi)的任意地方開始 GC 都是安全的

          OopMap(Ordinary Object Pointer,普通對象指針)

          • 如何確定 GC ROOT 的對象呢,檢查完所有執(zhí)行上下文和全局的引用位置?實際上 jvm 使用了 OopMap 記錄棧上本地變量到堆上對象的引用關(guān)系,避免從全局性引用和執(zhí)行上下文中逐個查找 GC ROOT,加快枚舉根節(jié)點的速度,幫助HotSpot實現(xiàn)準確式GC
          • JIT編譯過后的方法也會在一些特定的位置記錄下OopMap。特定的位置如下
            • 循環(huán)的末尾
            • 方法臨返回前 / 調(diào)用方法的call指令后
            • 可能拋異常的位置

          6 什么是 TLAB 和 PLAB ?

          TLAB

          堆內(nèi)存是所有線程共享的,jvm 在并發(fā)的環(huán)境進行內(nèi)存分配存在同步競爭,為了加快對象的分配創(chuàng)建,jvm 為每個線程分配了一個私有緩存區(qū)域(在Eden空間內(nèi)),這就是 Thread Local Allocation Buffer。使用TLAB可以避免一系列的非線程安全問題,同時還能夠提升內(nèi)存分配的吞吐量。如果私有 TLAB 使用完,則使用全局的

          PLAB

          PLAB 即 Promotion Local Allocation Buffers,用在年輕代對象晉升到老年代時。在多線程并行執(zhí)行 YGC 時,可能有很多對象需要晉升到老年代,為了加快內(nèi)存分配,于是有了 PLAB

          7 CMS、G1 新生代的 GC 如何避免全堆掃描?

          常見的 GC 利用了記憶集,記錄分代 GC中 老年代對象指向新年代對象的引用關(guān)系,以此避免掃描老年代對象區(qū)域

          • CMS 使用 CardTable(卡表)的數(shù)據(jù)結(jié)構(gòu)來標記老年代的某一塊內(nèi)存區(qū)域中的對象是否持有新生代對象的引用。point out 結(jié)構(gòu)
            • Card Table: 卡表的數(shù)量取決于老年代的大小和每張卡對應(yīng)的內(nèi)存大小,每張卡在卡表中對應(yīng)一個比特位,當(dāng)老年代中的某個對象持有了新生代對象的引用時,JVM就把這個對象對應(yīng)的Card所在的位置標記為dirty(bit位設(shè)置為1),這樣在Minor GC時就不用掃描整個老年代,而是掃描Card為Dirty對應(yīng)的那些內(nèi)存區(qū)域
          • G1 為了避免 young GC 時,掃描整個老年代,G1 引入了 Card Table 和 Remember Set 的概念
            • RSet:全稱 Remembered Sets, 用來記錄外部指向本 Region 的所有引用,每個 Region 維護一個 RSet。point in 結(jié)構(gòu),雙向指向
            • 下圖展示的是 RSet 與 Card Table 的關(guān)系。每個 Region 被分成了多個 Card Table,其中綠色部分的 Card 表示該 Card 中有對象引用了其他 Card 中的對象,這種引用關(guān)系用藍色實線表示。RSet 其實是一個 HashTable,Key 是 Region 的起始地址,Value 是 Card Table (字節(jié)數(shù)組),字節(jié)數(shù)組下標表示 Card 的空間地址,當(dāng)該地址空間被引用的時候會被標記為 dirty_card
          image.png

          為什么 G1 不維護年輕代到老年代的記憶集?

          • G1 分 young GC 和 mixed GC,full GC。young gc 會選所有年輕代的區(qū)域進行回收;midex gc 會選所有年輕代的區(qū)域和一些收集收益高的老年代區(qū)域進行回收,而full GC 則是全堆回收。三種 GC,年輕代的區(qū)域都在回收范圍內(nèi),所以不需要額外記錄年輕代到老年代的跨代引用

          8 CMS、G1 為了防止并發(fā)時的漏標分別用了什么手段?

          三色標志法

          • 黑色:從GCRoots開始,已掃描過它全部引用的對象,標記為黑色
          • 灰色:掃描過對象本身,還沒完全掃描過它全部引用的對象,標記為灰色
          • 白色:還沒掃描過的對象,標記為白色
          • 并發(fā)執(zhí)行漏標的兩個充分必要條件
            • 賦值器插入了一條或多條從黑色對象到白色對象的新引用
            • 賦值器刪除了全部從灰色對象到該白色對象的直接或間接引用

          漏標 CMS 解決方案-增量更新(Incremental Update)

          增量更新要破壞的是第一個條件,當(dāng)黑色對象插入新的指向白色對象的引用時,用寫屏障將新插入的引用記錄下來,等并發(fā)掃描結(jié)束之后,再以這些記錄過的黑色對象為根,重新掃描一次

          漏標 G1 解決方案-原始快照(Snapshot At TheBeginning,SATB)

          SATB 要破壞的是第二個條件,當(dāng)灰色對象要刪除指向白色對象的引用時,用寫屏障將這個要刪除的引用記錄下來,在并發(fā)掃描結(jié)束之后,再將這些記錄過的引用關(guān)系中的灰色對象為根,重新掃描一次

          9 什么是 logging write barrier

          • write barrier 的操作邏輯是復(fù)雜的,是為了減少對應(yīng)用 mutator 線程性能的影響,G1將一部分原本要在 write barrier 里做的邏輯分離出來交給異步線程并發(fā)執(zhí)行:mutator 線程在寫屏障里把分離的邏輯信息以 log 形式放到一個隊列里,然異步線程再從隊列里取出 log 批量執(zhí)行
          • 以SATB write barrier為例,每個Java線程有一個獨立的、定長的 SATBMarkQueue,mutator在 barrier 里把old_value壓入該隊列中。一個隊列滿了之后,它就會被加到全局的 SATB 隊列集合 SATBMarkQueueSet 里等待處理。后臺異步線程會掃描,如果超過一定閾值就會處理,開始處理

          10 CMS 常見問題

          最終標記階段停頓時間過長問題

          • CMS的GC停頓時間約80%都在最終標記階段(Final Remark),若該階段停頓時間過長,常見原因是新生代對老年代的無效引用,在 并發(fā)可取消預(yù)清理 階段中,執(zhí)行閾值時間內(nèi)未完成循環(huán),來不及觸發(fā) young GC,清理這些無效引用
          • 通過添加參數(shù):-XX:+CMSScavengeBeforeRemark。在執(zhí)行 Final Remark 操作之前先觸發(fā) young GC,從而減少新生代對老年代的無效引用,降低最終標記階段的停頓

          Promotion Failure

          • 該問題是在進行 young gc 時,Survivor Space放不下,對象只能放入老年代,而此時老年代也放不下,則會產(chǎn)生 Promotion Failure

          concurrent mode failure

          CMS 垃圾收集器特有的錯誤,CMS 的垃圾清理和引用線程是并行進行的,如果在并行清理的過程中老年代的空間不足以容納應(yīng)用產(chǎn)生的垃圾(也就是老年代正在清理,從年輕代晉升了新的對象,或者直接分配大對象年輕代放不下導(dǎo)致直接在老年代生成,這時候老年代也放不下),則會拋出 concurrent mode failure

          • 垃圾產(chǎn)生速度超過清理速度
            • 晉升閾值過小,設(shè)置 -XX:MaxTenuringThreshold=n
            • 降低觸發(fā)CMS GC的閾值,開啟根據(jù)閾值觸發(fā)CMS GC開關(guān):-XX:+UseCMSInitiatingOccupancyOnly,和參數(shù) -XX:CMSInitiatingOccupancyFraction=n 的值(默認為 92%),讓CMS GC盡早執(zhí)行,以保證有足夠的空間
            • 增加CMS線程數(shù),即參數(shù)-XX:ConcGCThreads
            • Survivor 空間過小,加大;Eden 區(qū)過小,加大。整體內(nèi)存下導(dǎo)致晉升速率提高,老年區(qū)空間不足
            • 存在大對象分配
          • CMS GC 發(fā)生 concurrent mode failure 時的 full GC 為什么是單線程的?
            • CMS GC 不兼容并發(fā)回收 young 區(qū)

          內(nèi)存碎片問題

          • 開啟空間碎片整理,并將空間碎片整理周期設(shè)置在合理范圍。開啟空間碎片整理 -XX:+UseCMSCompactAtFullCollection,讓CMS在進行一定次數(shù) Full GC 進行碎片壓縮 -XX:CMSFullGCsBeforeCompaction=n

          11 GC 事件和日志分析

          GC 指標

          • 延遲、GC 暫停時間(stop the world)
          • 吞吐量(應(yīng)用服務(wù)在非 GC 功能上運行的耗時百分比)
          • GC 頻率
          • CPU 耗時

          GC事件分類

          • Young GC, 新生代內(nèi)存的垃圾收集事件稱為Young GC(又稱Minor GC),當(dāng)JVM無法為新對象分配在新生代內(nèi)存空間時總會觸發(fā) Young GC
          • Old GC,只清理老年代空間的GC事件,只有CMS的并發(fā)收集是這個模式
          • Mixed GC,清理整個新生代以及部分老年代的GC,只有G1有這個模式
          • Full GC,清理整個堆的GC事件,包括新生代、老年代、元空間等

          GC日志分析

          • 開啟 GC 日志分析 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps

          需要對 GC 進行完整的監(jiān)控,監(jiān)控各年代占用大小、YGC 觸發(fā)頻率、Full GC 觸發(fā)頻率,對象分配速率等等

          GCLocker Initiated GC

          • 如果線程執(zhí)行在 JNI 臨界區(qū)時,剛好需要進行 GC,此時 GC Locker 將會阻止 GC 的發(fā)生,同時阻止其他線程進入 JNI 臨界區(qū),直到最后一個線程退出臨界區(qū)時觸發(fā)一次 GC

          動態(tài)擴容引起的空間震蕩

          • 服務(wù)剛剛啟動時 GC 次數(shù)較多,最大空間剩余很多但是依然發(fā)生 GC。在 JVM 的參數(shù)中?-Xms?和?-Xmx?設(shè)置的不一致,在初始化時只會初始?-Xms?大小的空間存儲信息,每當(dāng)空間不夠用時再向操作系統(tǒng)申請,這樣的話必然要進行一次 GC
          • 盡量將成對出現(xiàn)的空間大小配置參數(shù)設(shè)置成固定的,如?-Xms?和?-Xmx-XX:MaxNewSize?和?-XX:NewSize-XX:MetaSpaceSize?和?-XX:MaxMetaSpaceSize?等

          12 JVM 常用參數(shù)匯總

          • 通用配置參數(shù)
          參數(shù)說明實例
          -Xms初始堆大小,默認物理內(nèi)存的1/64-Xms512M
          -Xmx最大堆大小,默認物理內(nèi)存的1/4-Xms2G
          -Xmn新生代內(nèi)存大小,官方推薦為整個堆的3/8-Xmn512M
          -XX:NewRatio=n設(shè)置新生代和年老代的比值。如: 3,表示年輕代與年老代比值為1:3,年輕代占整個年輕代年老代和的1/4-XX:NewRatio=3
          -XX:SurvivorRatio=n年輕代中Eden區(qū)與兩個Survivor區(qū)的比值。注意Survivor區(qū)有兩個。如: 8,表示Eden:Survivor=8:1:1,一個Survivor區(qū)占整個年輕代的1/10-XX:SurvivorRatio=8
          -Xss線程堆棧大小,jdk1.5及之后默認1M,之前默認256k-Xss512k
          -XX:PermSize=n永久代初始值,默認為物理內(nèi)存的1/64-XX:PermSize=128M
          -XX:MaxPermSize=n永久代最大值,默認為物理內(nèi)存的1/4-XX:MaxPermSize=256M
          -verbose:class在控制臺打印類加載信息
          -verbose:gc在控制臺打印垃圾回收日志
          -XX:+PrintGC打印GC日志,內(nèi)容簡單
          -XX:+PrintGCDetails打印GC日志,內(nèi)容詳細
          -XX:+PrintGCDateStamps在GC日志中添加時間戳
          -Xloggc:filename指定gc日志路徑-Xloggc:/data/jvm/gc.log
          -XX:+DisableExplicitGC關(guān)閉System.gc()
          -XX:+UseBiasedLocking自旋鎖機制的性能改善
          -XX:PretenureSizeThreshold對象超過多大是直接在舊生代分配,默認值 0 ,單位字節(jié)
          -XX:TLABWasteTargetPercentTLAB 占eden區(qū)的百分比 默認值 1%
          -XX:+CollectGen0FirstfullGC 時是否先 youngGC ?默認值 false
          -XX:+PrintHeapAtGC打印 GC 前后的詳細堆棧信息
          -XX:ParallelGCThreads=n設(shè)置并行收集器時使用的CPU數(shù)。此值最好配置與處理器數(shù)目相等,同樣適用于CMS-XX:ParallelGCThreads=4
          • 年輕代
          參數(shù)說明
          -XX:+UseSerialGC年輕代設(shè)置串行收集器Serial
          -XX:+UseParallelGC年輕代設(shè)置并行收集器Parallel Scavenge
          -XX:UseParNewGC啟用ParNew收集器
          -XX:MaxTenuringThreshold幾次 youngGC 后會被分到老年代,默認是15次
          -XX:MaxGCPauseMillis=n年輕代垃圾回收的最長時間,如果無法滿足此時間,JVM會自動調(diào)整年輕代大小,以滿足此值
          • 老年代
          參數(shù)說明
          -XX:+UseParallelOldGC設(shè)置老年代為并行收集器ParallelOld收集器
          -XX:+UseConcMarkSweepGC設(shè)置老年代并發(fā)收集器CMS,且默認使用parNew作為新生代的垃圾回收
          -XX+UseCMSCompactAtFullCollectionfullGC過后,開啟對老年代的內(nèi)存壓縮,我們知道CMS使用的標記清除算法,會產(chǎn)生內(nèi)存碎片,所以需要內(nèi)存壓縮
          -XX:CMSFullGCsBeforeCompaction=n經(jīng)過幾次FullGC后進行內(nèi)存壓縮,默認是 0
          -XX:ParallelCMSThreads=nCMS 過程并發(fā)線程數(shù)
          -XX:+CMSParallelInitialMarkEnabled為了減少 CMS 初始標志暫停的時間,開啟并行標志
          -XX:+CMSParallelRemarkEnabled為了減少 CMS 第二次暫停的時間,開啟并行remark
          -XX:+CMSScavengeBeforeRemark如果 CMS remark 暫停時間過長的話,可以開啟該選項,強制remark之前開始一次minor gc,減少remark的暫停時間,但是在remark之后也將立即開始又一次minor gc
          • G1 特有參數(shù)
          參數(shù)說明
          -XX:+UseG1GC使用 G1 (Garbage First) 垃圾收集器
          -XX:InitiatingHeapOccupancyPercent老年代占用空間達到整堆內(nèi)存閾值(默認45%),則執(zhí)行新生代和老年代的混合收集(MixedGC),比如我們之前說的堆默認有2048個region,如果有接近1000個region都是老年代的region,則可能 就要觸發(fā)MixedGC了
          -XX:MaxGCPauseMillis目標暫停時間(默認200ms) 也就是垃圾回收的時候允許停頓的時間
          -XX:G1MixedGCCountTarget在一次回收過程中指定做幾次篩選回收(默認8次),在最后一個篩選回收階段可以回收一 會,然后暫停回收,恢復(fù)系統(tǒng)運行,一會再開始回收,這樣可以讓系統(tǒng)不至于單次停頓時間過長
          -XX:G1HeapWastePercent(默認5%) 在混合回收時,一旦空閑出來的Region數(shù)量達到了堆內(nèi)存的5%,此時就會立 即停止混合回收,意味著本次混合回收就結(jié)束了
          -XX:ConcGCThreads=n并發(fā)垃圾收集器使用的線程數(shù)量. 默認值隨JVM運行的平臺不同而不同

          歡迎指正文中錯誤

          參考文章

          • JVM(四)分代垃圾回收機制和垃圾回收算法?[1]
          • JVM(五) GC 底層細節(jié)[2]
          • ZGC設(shè)計與實現(xiàn)[3]
          • ?炸了!一口氣問了我18個JVM問題
          • concurrent mode failure[4]
          • 老大難的Java GC原理和調(diào)優(yōu),看這篇就夠了[5]
          • ?Java中9種常見的CMS GC問題分析與解決
          • 從實際案例聊聊Java應(yīng)用的GC優(yōu)化[6]
          • JDK 11 ZGC簡介[7]
          • JVM - 解讀GC中的 Safe Point & Safe Region[8]

          參考資料

          [1]

          JVM(四)分代垃圾回收機制和垃圾回收算法?: https://www.cnblogs.com/mouren/p/14361439.html

          [2]

          JVM(五) GC 底層細節(jié): https://www.cnblogs.com/mouren/p/14387192.html

          [3]

          ZGC設(shè)計與實現(xiàn): 書籍

          [4]

          concurrent mode failure: https://blog.csdn.net/muzhixi/article/details/105274542

          [5]

          老大難的Java GC原理和調(diào)優(yōu),看這篇就夠了: https://www.cnblogs.com/caison/p/11641791.html

          [6]

          從實際案例聊聊Java應(yīng)用的GC優(yōu)化: https://tech.meituan.com/2017/12/29/jvm-optimize.html

          [7]

          JDK 11 ZGC簡介: https://www.cnblogs.com/ctgulong/p/9742434.html

          [8]

          JVM - 解讀GC中的 Safe Point & Safe Region: https://blog.csdn.net/yangshangwei/article/details/107119177


          瀏覽 53
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄色成人网站在线免费看 | 不卡操逼| 国产一级a毛一级a看免费视频乱 | 激情精品| 久久看黄色视频 |