一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 【后端面經-Java】JVM垃圾回收機制

【后端面經-Java】JVM垃圾回收機制

2023-09-15 02:18未知服務器之家 Java教程

本文對JVM垃圾回收機制做了詳細解釋,從"where"、"whice"、"when"、"why"、"how"、"who"的角度,重點介紹JVM垃圾回收機制的觸發機制、垃圾判斷算法、垃圾回收算法和垃圾回收機制。 目錄 1. Where:回收哪里的東西?——JVM內存分配 2. Wh

【后端面經-Java】JVM垃圾回收機制 本文對JVM垃圾回收機制做了詳細解釋,從"where"、"whice"、"when"、"why"、"how"、"who"的角度,重點介紹JVM垃圾回收機制的觸發機制、垃圾判斷算法、垃圾回收算法和垃圾回收機制。

目錄
  • 1. Where:回收哪里的東西?——JVM內存分配
  • 2. Which:內存對象中誰會被回收?——GC分代思想
    • 2.1 年輕代/老年代/永久代
    • 2.2 內存細分
  • 3. When:什么時候回收垃圾?——GC觸發條件
  • 4. Why:憑什么說它是垃圾?——垃圾判斷算法
    • 4.1 引用計數法
    • 4.2 可達性分析法
  • 5. How:如何對待垃圾?——垃圾回收算法
    • 5.0 垃圾的垂死掙扎
    • 5.1 標記-清除算法
    • 5.2 標記-整理算法
    • 5.3 復制算法
    • 5.4 分代收集算法
  • 6. Who:誰去處理垃圾?——垃圾回收器
    • 6.1 年輕代-Serial收集器
    • 6.2 年輕代-ParNew收集器
    • 6.3 年輕代-Parallel Scavenge收集器
    • 6.4 老年代-SerialOld收集器
    • 6.5 老年代-ParallelOld收集器
    • 6.6 老年代-CMS(Concurrent Mark Sweep)收集器
    • 6.7 年輕代和老年代-G1(Garbage First)收集器
    • 6.8 垃圾回收器對比圖
  • 面試模擬
  • 參考資料

1. Where:回收哪里的東西?——JVM內存分配

JVM垃圾回收機制(Garbage Collect,簡稱GC)主要負責回收JVM內存當中未被及時釋放回收的內存區域,JVM垃圾回收機制讓程序員擺脫了手動釋放內存的操作,降低了程序員疏忽大意導致的風險。
那么,垃圾回收機制到底針對哪一塊的內存空間進行處理呢?是整體內存還是某一塊內存?
在回答這個問題之前,我們需要先了解一下JVM內存分配機制,JVM內存分配機制主要有如下幾個區域:

  • 棧(Stack)
  • 堆(Heap)
  • 方法區(Method Area)
  • 本地方法棧(Native Method Stack)
  • 程序計數器(PC)
    我們需要知道的是,棧、本地方法棧、程序計數器和方法調用有關,是線程私有的,隨著方法結束,棧和本地方法棧的棧幀會出棧,釋放內存,因此,這三部分并不需要使用垃圾回收機制。
    而堆主要存放對象實例和數組,而方法區存放類的信息、編譯信息、常量池等,這兩塊區域由于是線程共享的,在方法調用結束之后也不會被釋放內存(畢竟A用完了,不知道B、C、D會不會用到這部分)需要使用垃圾回收機制進行內存回收。

關于每個區域的具體內容,可參考博客:【后端面經-Java】JVM內存分區詳解

因此,內存回收機制主要針對堆和方法區進行處理。

2. Which:內存對象中誰會被回收?——GC分代思想

2.1 年輕代/老年代/永久代

JVM垃圾回收機制中,一般都是基于GC分代思想進行算法設計。
GC機制將內存內容分為三部分:

  • 年輕代(Young Generation):新產生的實例基本上都處于這代,因為新產生的實例大部分都是一次性的,因此這部分內存需要經常進行內存回收;
  • 老年代(Old Generation):在新生代殘酷頻繁的篩選機制中,多次存活下來的實例會進入老年代,老年代意味著生命周期較長,一般在內存沒有滿之前不會對這部分內存進行回收;
  • 永久代(Permanent Generation,JCK1.8之后改成元空間(Metaspace)):永久代存放的是JVM程序運行相關的元數據,比如類信息、方法信息、常量池等,內容重要且占空間小,因此基本上不會進行垃圾回收。

如果要類比的話,年輕代就是剛剛步入職場的小青年,不穩定性較高,很容易被裁員(垃圾回收),而熬過這個階段,成為技術骨干(老年代)之后,基本上不會在正常公司運行過程中被裁員,除非公司倒閉(內存已滿),而永久代或者元空間就是公司最高層的管理人員,對公司的運行起著關鍵作用,一般情況下不會被裁員。

2.2 內存細分

  1. 堆和方法區
    堆中存放年輕代和老年代,而方法區中存放永久代。
  2. 新生代區域細分
    新生代區域又分為Eden區Survivor0區Survivor1區,比例為8:1:1

整體內存細分情況如圖所示:
【后端面經-Java】JVM垃圾回收機制

3. When:什么時候回收垃圾?——GC觸發條件

GC按照觸發條件,可分為Scavenge GCFull GC

  • Scavenge GC(Minor GC)
    Scavenge GC是指年輕代Eden區的垃圾回收,觸發條件為:
    • 年輕代Eden區域內存不足
      • 調用Scavenge GC之后,將未清理的元素放入Survivor0區域。如果Survivor0區域內存不足,則將Survivor0區域內存中的所有元素放入Survivor1區域。清空Survivor0區域,然后將Survivor1中的元素放入Survivor0中;
      • 如果Survivor1區域內存不足,則將Survivor1區域內存中的所有元素放入老年代中;
      • 如果老年代也內存不足,則會考慮觸發Full GC。
  • Full GC(Major GC)
    Full GC是整體對內存的垃圾回收,包括年輕代和老年代,觸發條件為:
    • 老年代內存不足
    • 永久代內存不足
    • 顯性調用system.gc()
    • 上次GC之后堆內存的劃分出現變化

對于GC線程,其本身的優先級比較低,因此在CPU空閑的時候,可能會進行GC處理,而在忙時基本上不會進行GC處理,除非此時內存空間不足,需要GC處理之后才能正常運行。
Full GC對于計算資源是一個很大的消耗,應該盡量避免使用Full GC。

4. Why:憑什么說它是垃圾?——垃圾判斷算法

前面主要介紹了JVM垃圾回收機制的針對對象,GC分代思想和觸發條件。那么,好好的一個對象實例,GC機制空口無憑憑什么說它是垃圾呢?這就需要垃圾判斷算法了。
常見的垃圾判斷方法有兩種:引用計數法可達性分析法

4.1 引用計數法

  • 每個對象實例都有一個引用計數器,當有一個引用指向該對象實例時,引用計數器加1,當引用失效時,引用計數器減1,當引用計數器為0時,該對象實例就是垃圾,需要進行回收。
  • 補充一下JVM的引用類型,如下圖所示:
  • 優點:判斷邏輯簡單;
  • 缺點:無法解決循環引用的問題(從圖論角度來說就是環狀節點無法識別)。

4.2 可達性分析法

  • 將每個實例看作節點,兩個實例之間的引用關系看作路徑。從GC Roots開始,對堆內存中的對象進行遍歷,如果某個對象實例沒有被遍歷到,則說明該對象實例不可達,不可達則是垃圾,對其進行垃圾標記,等待后續回收(非連通圖查找連通子圖的數量)。
  • GC Roots指的是正在運行的程序中一些基本對象,從這些對象往下查找其引用對象,包括如下幾種:
    • 虛擬機棧(棧幀中的本地變量表)中引用的對象
    • 方法區中類靜態屬性引用的對象
    • 方法區中常量引用的對象
    • 本地方法棧中JNI(Native方法)引用的對象
  • 優點:能有效解決循環引用的問題;
  • 缺點:判斷邏輯復雜,需要遍歷整個內存空間,效率較低。

5. How:如何對待垃圾?——垃圾回收算法

常見的垃圾回收算法包括:標記-清除算法標記-整理算法復制算法分代收集算法(自適應算法)。

5.0 垃圾的垂死掙扎

在被處決之前,垃圾會進行一次垂死掙扎,實例第一次被標記為垃圾之后,如果可以進行一次有效finalize()方法調用,和其他實例建立引用,那么該實例就會被復活,不會被回收。

5.1 標記-清除算法

在垃圾判斷算法執行完成后,已經被明確判斷成垃圾的實例,清除法在原地釋放其內存空間,將其標記為可用空間,等待后續的內存分配。

  • 優點:操作簡單,原地清除不需要復制內存
  • 缺點:會產生內存碎片,長期運行會影響CPU運行效率

5.2 標記-整理算法

標記-整理算法在標記完成之后,將所有存活的實例移動到一端,然后清除掉另一端的內存空間,這樣就可以有效解決內存碎片的問題。

  • 優點:無內存碎片;
  • 缺點:需要移動實例,效率較低;

5.3 復制算法

復制算法將內存空間分為兩塊,每次只使用其中一塊,當一塊內存空間內存滿了之后,將存活的實例復制到另一塊內存空間中,然后清除掉之前的內存空間。

  • 優點:無內存碎片,操作簡單;標記和復制可并行;
  • 缺點:可用內存空間直接減半,內存利用率較低;

5.4 分代收集算法

針對不同代的數據特點,使用不同的垃圾回收算法。

  • 年輕代:復制算法
    • 存活對象較少,復制算法每次的對象復制不會有太大負擔;
    • 操作頻繁,復制算法標記和復制可并發處理,效率較高;
  • 老年代:標記-整理算法
    • 存活對象較多,減少內存碎片,提高可用性
  • 永久代(元空間):不作考慮

6. Who:誰去處理垃圾?——垃圾回收器

垃圾回收器是垃圾回收算法的執行者,常見的垃圾回收器如下圖所示:
【后端面經-Java】JVM垃圾回收機制

連線部分說明這兩個垃圾回收器能夠搭配使用。

6.1 年輕代-Serial收集器

  • 回收算法:復制算法
  • 單線程:執行回收算法的時候是單線程;適用于并發能力較低的系統。
  • Stop the World:一般線程和回收線程無法并行,執行回收算法需要中斷其他線程,這個現象稱為Stop the World(亂入Dio的“咋瓦魯多”)。
    • Stop the World現象會導致系統暫停,引出垃圾收集停頓時間這一參數,影響用戶體驗,因此需要盡量避免;
  • 優點:簡單高效,適用于單核CPU;
  • 缺點:無法并行,且單線程處理效率較低;
  • 啟用方式:-XX:+UseSerialGC

6.2 年輕代-ParNew收集器

  • 回收算法:復制算法
  • 多線程:執行回收算法的時候是多線程;
  • 也會存在Stop the World現象,除了多線程的改進之外,和Serial收集器沒有太大區別;
  • 優點:多線程處理效率高,適用于多核CPU;
  • 缺點:一般線程和回收線程無法并行處理;
  • 啟用方式:-XX:+UseParNewGC

6.3 年輕代-Parallel Scavenge收集器

  • 回收算法:復制算法
  • 關注吞吐量
    吞吐量 = 用戶線程運行時間 / (用戶線程運行時間 + 垃圾回收線程運行時間)
    
  • 相關參數
      1. 垃圾收集停頓時間
      • 設置方式:-XX:MaxGCPauseMillis=一個數值
      • 停頓時間過大將會直接影響每次垃圾回收的用戶體驗,停頓時間過小則會導致垃圾回收頻繁;
      1. 吞吐量大小
      • 設置方式:-XX:GCTimeRatio=一個數值
      • 默認取值為99%,表示只有1%的時間用于垃圾回收;
      1. 自適應模式
      • 設置方式:-XX:+UseAdaptiveSizePolicy
      • 設置自適應模式之后,內存中的新生代分配比例和老年代的時間參數可自行調整,達到吞吐量、停頓時間和內存占用的平衡;
  • 是JDK1.8的默認垃圾回收器
  • 啟用方式:-XX:+UseParallelGC

6.4 老年代-SerialOld收集器

  • 回收算法:標記-整理算法
  • 單線程,可類比年輕代的Serial收集器,優缺點同理
  • CMS收集器的后備算法

6.5 老年代-ParallelOld收集器

  • 回收算法:標記-壓縮算法
  • 關注吞吐量,可類比年輕代的Parallel Scavenge收集器
  • 多線程,線程數通過-XX:ParallelGCThreads設置,默認為CPU核心數
  • 啟用方式:-XX:+UseParallelOldGC

6.6 老年代-CMS(Concurrent Mark Sweep)收集器

  • 回收算法:標記-清除算法
  • 關注停頓時間,期望有較短的垃圾回收停頓時間,從而優化用戶體驗;
  • 回收步驟:
    • 初始標記:適用可達性分析法的思想,標記GC Roots能直接關聯到的對象,速度較快;
    • 并發標記:一般線程和回收線程并行,對此時標記狀態出現變化的實例進行統計;
    • 重新標記:根據并發標記的結果,對標記狀態發生變化的實例進行重新標記,這一步相對較慢;
    • 并發清除:清理垃圾實例,釋放內存空間;這一步可以和一般線程并行;
  • 相關參數:
    • 觸發閾值:
      • 設置方式:-XX:CMSInitiatingOccupancyFraction=一個數值
      • 和之前討論的何時進行垃圾回收的觸發機制不同,CMS在處理老年代的時候,不會等到內存完全占滿,而是會設置一個閾值,默認數值為68%,占用內存空間超過這個閾值就進行垃圾回收處理。
    • 整理標記
      • 設置方式:-XX:+UseCMSCompactAtFullCollection
      • 如果設置這一標記,則垃圾回收之后會進行一次整理,合并內存碎片。
  • 優點:并發收集,提高執行效率;減少停頓時間,用戶體驗佳
  • 缺點:無法處理浮動垃圾,對CPU資源敏感,且標記清除算法會產生內存碎片

6.7 年輕代和老年代-G1(Garbage First)收集器

  • 回收算法:整體來看是標記-整理算法,局部來看是復制算法
  • 關注停頓時間,也關注高吞吐量(我全都要.jpg);
  • 分區:不同于之前所討論的分代劃分內存區域的方式,G1回收器將內存劃分為一個又一個單元區域,稱為Region
    • 設置方式:-XX:G1HeapRegionSize=一個數值
    • 每個分區內部可以存放年輕代或者老年代的數據,根據不同的存放數據,將分區劃分為四類:
      • E-Eden區:存放年輕代當中Eden區域的數據;
      • S-Survivor區:存放年輕代當中Survivor區域(survivor0和survivor1)的數據;
      • O-Old:存放老年代的一般數據;
      • H-Humongous:存放老年代當中大對象的數據;當占據整個Region一半以上的時候,就會被劃分為Humongous區域;
  • 停頓預測模型:用戶可以自行設置垃圾回收停頓時間,而G1回收器會根據歷史數據構建預測模型,考慮為了滿足用戶設置的停頓時間,本次垃圾回收可以處理哪幾個Region。
  • Region優先級隊列:G1瀏覽器維護一個Region隊列,高價值的Region有更高的優先級,在垃圾回收的時候優先處理,這也是Garbage First名字的由來。
  • 回收步驟(和CMS回收器類似):
    • 初始標記
    • 并發標記
    • 重新標記
    • 并發清除
  • 優點:并發操作,并行收集,提高執行效率;關注停頓時間,可預測停頓時間,優化用戶體驗;可處理浮動垃圾,不會產生內存碎片;

6.8 垃圾回收器對比圖

對上述垃圾回收器的對比如下所示:
【后端面經-Java】JVM垃圾回收機制

面試模擬

Q:介紹一下JVM和垃圾回收機制。
A:從"where"、"whice"、"when"、"why"、"how"、"who"的角度,重點介紹觸發機制/判斷算法/垃圾回收算法/垃圾回收機制

參考資料

  1. JVM之垃圾回收機制(GC)
  2. JVM的垃圾回收機制 總結(垃圾收集、回收算法、垃圾回收器)
  3. 深入理解 JVM 垃圾回收機制及其實現原理

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 日本xnxnxnxnxn护士 | 久久精品99国产精品日本 | 女人扒开下面让男人桶爽视频 | 日韩欧美亚洲一区二区综合 | 3d美女触手怪爆羞羞漫画 | 免费观看a毛片一区二区不卡 | 欧美一区二区三 | 免费一级国产生活片 | 思思91精品国产综合在线 | 久久久久久免费高清电影 | 亚洲a视频在线观看 | 男人的j插入女人的p | 精品久久99麻豆蜜桃666 | 摔跤成人黄版 | 国产青草视频在线观看免费影院 | 被老头肉至怀孕小说 | 国产精品久久亚洲一区二区 | 色老板影视 | 欧美日韩中文国产一区二区三区 | 91视频a | 婷婷激情综合五月天 | 麻豆天美精东果冻传媒在线 | 骚虎网站在线观看 | 免费视频一区 | 日本mv精品中文字幕 | 日韩去日本高清在线 | 99成人国产精品视频 | 青春娱乐国产分类精品二 | 人体欣赏孕妇季玥图片 | 国产综合久久久久 | 91香蕉导航| 国产日日干 | 久久久久久久久女黄 | 99久久99热久久精品免 | 亚洲视频在线一区二区三区 | 91天堂素人97年清纯嫩模 | 亚洲成人免费看 | 婷婷在线综合 | 亚洲免费视频在线 | 国产精品成人在线播放 | 亚洲AV国产福利精品在现观看 |