JVM系列垃圾回收機制(Garbage Collect)

      網友投稿 749 2022-05-30

      JVM系列之垃圾回收機制(Garbage Collect)

      1、前言介紹

      在前面章節的學習中,我們知道了java虛擬機的運行時數據區和類加載機制,了解了在堆內存中是有垃圾回收的,比如young區的Minor GC,Old區的Major GC,young區和old區的full GC。

      對于一個內存中的對象,怎么確定它需要回收的?怎么樣對它進行回收?

      2、如何確定一個對象需要回收?

      對于引用計數法而言,只要應用程序中持有對該對象的引用,則這個對象不需要回收,如果這個對象沒有任何指針對其引用,則這個對象需要回收。

      弊端:如果對象A和B之間相互持有引用,會導致永遠不會被回收

      寫個例子進行驗證:

      public class TestGc { static class A{ public B b; } static class B { public A a; } public static void testGc() { A a = new A(); B b = new B(); a.b = b; b.a = a; a = null; b = null; // 強制進行gc回收 System.gc(); } public static void main(String[] args) { testGc(); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      添加java虛擬機參數-XX:+PrintGC,在控制臺打印出gc日志

      從日志可以看出,在jdk8里還是有進行回收的,說明jdk8默認的回收機制不是基于“引用計數法”的

      [GC (System.gc()) 4301K->1033K(117760K), 0.0024682 secs] [Full GC (System.gc()) 1033K->990K(117760K), 0.0170595 secs]

      1

      2

      通過GC Root的對象,開始向下尋找,看某個對象是否可達,能查找到就是可達

      在Java技術體系里面,固定可作為GC Roots的對象有:

      虛擬機棧引用的對象

      方法區中類靜態屬性引用的對象

      方法區中常量引用的對象

      本地方法棧中JNI(Native方法)引用的對象

      ·所有被同步鎖(synchronized)持有的對象

      類加載器、Thread、基本數據類型對應的Class對象、常駐的異常對象

      等等

      3、什么時候會垃圾回收?

      (1)、當Eden區或者S區不夠用時

      (2)、old區空間不夠用時

      (3)、方法區空間不夠用時

      (4)、System.gc() 手動回收(通知回收,什么時候回收由jvm決定,生產環境不建議使用,因為gc消耗的資源比較大)

      4、 垃圾收集算法

      標記Mark

      找出內存中需要回收的對象,并且將它們標記出來

      JVM系列之垃圾回收機制(Garbage Collect)

      引用官網圖片:

      清除(Sweep)

      清除掉被標記需要回收的對象,釋放出對應的內存空間

      將不需要回收的對象,如圖Referenced對象復制到S0,然后清理Eden,當然Young區的垃圾回收,還有沒那么簡單,這里不詳細描述(為什么要兩個S區的原因可以找上一章學習)

      同樣需要標記的過程:

      讓所有Referenced對象都向一端移動,清理掉邊界意外的內存。

      5、 分代垃圾收集過程

      在前面的學習中,我們知道了堆是jvm一個很重要的部分,堆可以分為young區(“新生代”)和old區(“老年代”),young區再細分為Eden區、S0區(From區)、S1區(To區),然后對象是怎么進行分代分配收集的,然后按照官網描述走一遍流程,圖來自官網

      1、任何新對象最開始都被分配到 eden 空間。兩個幸存者空間一開始都是空的,圖來自官網

      2、伊甸園空間填滿時,會觸發一個次要的垃圾收集

      3、引用的對象會被移到S0區,然后清理Eden區,未引用的對象被清理

      4、在下一次的小GC中,Eden區引用的對象同樣會移到幸存區,不過這次不是S0(From)區,而是S1(To)區。同時原來S0(From)區中的引用對象達到一個閾值后,也會被移到S1區,當所有符合條件的引用對象都被移到S1時,就會觸發GC,清理Eden區、S0區的對象

      5、在接下來的下一個次要(minor )GC,會重復同樣的過程。不過這一次,幸存區被換了,這次換成S0區,Eden區引用的對象和S1中的引用對象被移到S0區,然后清理Eden區和S1區

      6、前面就是young區的minor GC大概過程,當對象達到一定的年齡閾值(本例中為8)時,它們會從“年輕代“提升到“老年代“。

      7、 隨著次要 GC 的繼續發生,對象將繼續被提升到老年代空間

      8、如果old區空間滿了,將在old區執行一次major GC,清理并壓縮該空間

      6、 垃圾收集器

      垃圾收集算法是方法論,垃圾收集器就是內存回收的具體實現,按照并行多線程、作用 范圍(作用于“新生代”還是“老年代”),可以細分為各類的垃圾收集器

      young Generation Collection:

      Serial

      Serial收集器是最基本,發展歷史最早的收集器,在jdk1.3.1之前是java虛擬機唯一的選擇,它是一種單線程的收集器,采用復制算法。

      ParNew

      ParNew是一種多線程版本的收集器,也是采用復制算法的收集器,可以理解為Serial的多線程版本。

      Parallel Scavenge

      Parallel Scavenge 也是一種復制類型的收集器,支持多線程并發,看起來和ParNew有點像,不過Parallel Scanvenge更關注系統的吞吐量。

      Old Generation Collection

      Serial Old

      Serial Old收集器是Serial收集器的老年代版本,也是一個單線程收集器,采用的收集算法是“標記-整理”,“mark-sweep-compact”,運行過程和Serial一樣

      CMS

      Concurrent Mark Sweep(CMS),是一種以獲取 最短回收停頓時間 為目標的收集器,采用的是標記-清除算法,官方文檔

      整個過程分為4:

      (1)、初始標記(CMS initial mark):標記GC roots直接關聯對象,不需要Tracing,速度是很快的

      (2)、并發標記(CMS concurrent mark):這個過程會進行GC Roots tracing

      (3)、重新標記(CMS remark):重新標記并發標記中因用戶程序改變的內容

      (4)、并發清楚(CMS concurrent sweep):這個過程會清理不可達的對象,回收內存空間(不過這個過程會產生新垃圾,留著下次清理,這個被稱之為浮動垃圾)

      注意:總體上來說,CMS收集器的內存回收過程是與用戶線程一起并發地執行的,因為整體過程,并發標記和并發清除,收集器線程可以與用戶線程一起工作

      Parallel Old

      Parallel Old收集器是Parallel Scavenge收集器的老年代版本,支持多線程,使用“標記-整理算法”進行垃圾回收,也是更加關注系統的吞吐量

      G1

      Garbage-First (G1) 收集器是一種服務器式垃圾收集器,適用于具有大內存的多處理器機器。

      G1收集器,Java堆的內存布局和其它收集器有很大差別,它將整個java堆劃分為多個大小相等的獨立區域(Region),雖然還保留著“新生代”和“老年代”的概念,不過“新生代”和“老年代”不再是以前的設計模型,而是很大Region區域的集合。所謂Garbage-Frist,其實就是優先回收垃圾最多的Region區域。

      引用官網的圖例:

      每個Region大小都是一樣的,可以是1M到32M之間的數值,但是必須保證是2的n次冪,如果對象太大,一個Region放不下,超過了Region大小的50%,就會直接放到H中

      注意:設置Region大小:-XX:G1HeapRegionSize=M

      G1收集器收集過程:

      初始標記(Initial Marking) 標記以下GC Roots能夠關聯的對象,并且修改TAMS的值,需要暫停用戶線程

      并發標記(Concurrent Marking) 從GC Roots進行可達性分析,找出存活的對象,與用戶線程并發執行

      最終標記(Final Marking) 修正在并發標記階段因為用戶程序的并發執行導致變動的數據,需暫停用戶線程

      篩選回收(Live Data Counting and Evacuation) 對各個Region的回收價值和成本進行排序,根據用戶所期望的GC停頓時間制定回收計劃

      ZGC

      The Z Garbage Collector (ZGC)是一種可擴展的低延遲垃圾收集器。是自從JDk11才有的,不管是物理上還是邏輯上,ZGC中已經不存在新老年代的概念了。它的數據結構會分為一個個page,當進行GC操作時會對page進行壓縮,因此沒有碎片問題。只能在64位的linux上使用,目前用得還是比較少的

      注意:開啟命令,XX:+UnlockExperimentalVMOptions -XX:+UseZGC。

      比較詳細地學習了各類垃圾收集器之后,需要進行歸類總結一下知識點,按照垃圾收集器的作用范圍,作用于“新生代”還是“老年代”可以分為如圖所示:

      引用官網webfolder PDF的圖片:

      只作用于“新生代”的有Serial、ParNew、ParalleScavenge;只作用于“老年代”的有Serial Old、CMS、Parallel Old;同時可以作用于“新生代”和“老年代”的有G1

      按照是否支持并發的,可以分為串行收集器和并行收集器

      串行收集器

      Serial和Serial Old,只有一個垃圾回收線程執行,執行期間用戶線程暫停,適用于內存比較小的嵌入式設備

      并行收集器[吞吐量優先]

      Parallel Scanvenge、Parallel old,多個線程執行,此時用戶線程仍然處于等待狀態。

      并行收集器[停頓時間優先]

      CMS、G1,用戶線程和垃圾收集線程同時執行,但并不一定是并行的,可能是交替執行的,垃圾收集線程在執行的時候不會停頓用戶線程的運行

      Java JVM 任務調度

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:深入小程序系列之二、Flutter 和小程序混編
      下一篇:什么是事務數據庫?丨【綻放吧!數據庫】
      相關文章
      亚洲欧美成aⅴ人在线观看| 亚洲电影在线免费观看| 久久亚洲私人国产精品| 久久被窝电影亚洲爽爽爽| 国产精品亚洲精品日韩动图| 亚洲色大网站WWW永久网站| 亚洲人成在线精品| 亚洲精品人成电影网| 亚洲福利视频网址| 亚洲福利电影一区二区?| 在线电影你懂的亚洲| 亚洲视频免费在线看| 亚洲欧洲国产日韩精品| 亚洲综合图片小说区热久久| 亚洲高清日韩精品第一区| 亚洲大香人伊一本线| 亚洲日韩国产精品乱-久| 亚洲日韩国产二区无码| 亚洲AV无码成人精品区狼人影院 | 亚洲第一AV网站| 久久国产亚洲电影天堂| 亚洲毛片在线观看| 亚洲免费在线视频播放| 亚洲AV成人一区二区三区在线看| 亚洲一卡2卡三卡4卡无卡下载 | 亚洲国产免费综合| 亚洲精品蜜桃久久久久久| 亚洲国产综合专区电影在线| 亚洲视频一区在线| 亚洲AV无码精品蜜桃| 亚洲欧美日韩中文字幕一区二区三区| 亚洲精品无码专区在线播放| 国产成人亚洲毛片| 久久亚洲国产成人影院网站| 日韩va亚洲va欧洲va国产| 亚洲综合图片小说区热久久| 精品国产日韩久久亚洲| 在线观看亚洲专区| 亚洲一区二区三区无码中文字幕| 久久亚洲AV无码精品色午夜麻| 亚洲国产视频一区|