日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

被說爛了的Java垃圾回收算法,我帶來了最“清新脫俗”的詳細圖解

 

一、概況

理解JAVA虛擬機垃圾回收機制的底層原理,是系統調優與線上問題排查的基礎,也是一個高級Java程序員的基本功,本文就針對Java垃圾回收這一主題做一些整理與記錄。Java垃圾回收器的種類繁多,它們的設計要在吞吐量(內存空間)與實時性(用戶線程中斷)方面進行權衡,各個垃圾回收器的適應場景也不盡相同(如:桌面應用,web應用),因此,這里我們只討論JDK8下的默認垃圾回收器,畢竟目前JDK8版本是業界的主流(占80%),并且我們只討論堆內存空間的垃圾回收。

JDK8下的默認垃圾回收器:UseParallelGC : Parallel (新生代)+ (老年代)堆內存回收機制

二、如何判斷對象是否可回收?

首先思考一個問題,內存堆中那么多對象,回收器要回收哪些對象?怎么判斷出這些要回收的對象呢?因此對于垃圾回收,判斷并標識對象是否可回收是第一步。從理論層面來說,判斷對象是否可回收一般兩種方法。

第一種、引用計數器算法:每當對象被引用一次計數器加1,對象失去引用計數器減1,計數器為0是就可以判斷對象死亡了。這種算法簡單高效,但是對于循環引用或其他復雜情況,需要更多額外的開銷,因此Java幾乎不使用該算法。

第二種、根搜索算法-可達性分析算法:所謂可達性分析是指順著GCRoots根一直向下搜索(用一個成語概括就是“順藤摸瓜”),整個搜索的過程就構成了一條“引用鏈”,只要在引用鏈上的對象叫做可達,在引用鏈之外的(說明跟GCRoots沒有任何關系)叫不可達,不可達的對象就可以判斷為可回收的對象。 哪些對象可作為GCRoots對象呢? 包括如下:

  • 虛擬機棧幀上本地變量表中的引用對象(方法參數、局部變量、臨時變量)
  • 方法區中的靜態屬性引用類型對象、常量引用對象
  • 本地方法棧中的引用對象(Native方法的引用對象)
  • Java虛擬機內部的引用對象,如異常對象、系統類加載器等
  • 所以被同步鎖(synchronize)持有的對象
  • Java虛擬機內部情況的注冊回調、本地緩存等

如果對虛擬機的內存布局與運行流程有所了解的話,這些作為GCRoots都很好理解,它們是程序運行時的源頭,程序的正常運行必須依賴它們,而與這些源頭沒有任何關系的對象,即可視為可回收對象。就好比“瓜從藤上掉下來了, 那這瓜肯定也沒有用了”

被說爛了的Java垃圾回收算法,我帶來了最“清新脫俗”的詳細圖解

?GCRoots可達性分析 不可達對象


被說爛了的Java垃圾回收算法,我帶來了最“清新脫俗”的詳細圖解

可達性分析

可達性分析從理論上很好理解,但在垃圾收集器具體運行時,要考慮的問題不知道要復雜多少倍,因為在可達性分析的同時,程序也是在并行運行著,整個內存堆的狀態隨著程序的運行是實時變化的,要實

現分析結果與內存狀態的一致性,就必須要暫停用戶線程,在一個快照去進行分析。

三、垃圾回收算法

可達性分析解決了判斷對象是否可回收的問題,那么在垃圾回收時內存空間會發生哪些變化呢?這就是垃圾回收算法要討論的問題,我們根據算法對內存采取的不同操作,可將垃圾回收算法分為3種,標記-清除算法、標記-復制算法、標記-整理算法。

3.1 標記-清除算法

根據名稱就可以理解改算法分為兩個階段:首先標記出所有需要被回收的對象,然后對標記的對象進行統一清除,清空對象所占用的內存區域,下圖展示了回收前與回收后內存區域的對比,紅色的表示可回收對象,橙色表示不可回收對象,白色表示內存空白區域。

被說爛了的Java垃圾回收算法,我帶來了最“清新脫俗”的詳細圖解

標記-清除算法 垃圾回收前后內存區域對比

標記-清除算法的兩個缺點:

第一個:是執行效率不可控,試想一下如果堆中大部分的對象都可回收的,收集器要執行大量的標記、收集操作。

第二個:產生了許多內存碎片,通過回收后的內存狀態圖可以知道,被回收后的區域內存并不是連續的,當有大對象要分配而找不到滿足大小的空間時,要觸發下一次垃圾收集。

 

3.2 標記-復制算法

針對標記-清除算法執行效率與內存碎片的缺點,計算機科學家又提出了一種“半復制區域”的算法。

標記-復制算法將內存分為大小相同的兩個區域,運行區域,預留區域,所有創建的新對象都分配到運行區域,當運行區域內存不夠時,將運作區域中存活對象全部復制到預留區域,然后再清空整個運行區域內存,這時兩塊區域的角色也發生了變化,每次存活的對象就像皮球一下在運行區域與預留區域踢來踢出,而垃圾對象會隨著整個區域內存的清空而釋放掉,內存前后的狀態參考下圖:

被說爛了的Java垃圾回收算法,我帶來了最“清新脫俗”的詳細圖解

?標記-復制算法回收前后內存對比

標記-復制算法在大量垃圾對象的情況下,只需復制少量的存活對象,并且不會產生內存碎片問題,新內存的分配只需要移動堆頂指針順序分配即可,很好的兼顧了效率與內存碎片的問題。

標注-復制算法也存在缺點

預留一半的內存區域未免有些浪費了,并且如果內存中大量的是存活狀態,只有少量的垃圾對象,收集器要執行更多次的復制操作才能釋放少量的內存空間,得不償失。

 

3.3 標記-整理算法

標記-復制算法要浪費一半內存空間,且在大多數狀態為存活狀態時使用效率會很低,針對這一情況計算機科學家又提出了一種新的算法“標記-整理算法”,標記整理算法的標記階段與其他算法一樣,但是在整理階段,算法將存活的對象向內存空間的一端移動,然后將存活對象邊界以外的空間全部清空,如下圖所示:

被說爛了的Java垃圾回收算法,我帶來了最“清新脫俗”的詳細圖解

?標記-整理算法回收前后內存對比

標記整理算法解決了內存碎片問題,也不存在空間的浪費問題,看上去挺美好的。但是,當內存中存活對象多,并且都是一些微小對象,而垃圾對象少時,要移動大量的存活對象才能換取少量的內存空間。

不同的垃圾回收算法都有各自的優缺點,適應于不同的垃圾回收場景

 

四、新生代、老年代堆內存結構

Java 堆內存空間新生代、老年代是如何劃分的?對象創建后是如何分配到不同的區域的?結合下圖可以知道,整個堆內存被分為了2個大的區域,新生代,老年代,默認情況下新生代占1/3的空間,老年代占2/3的空間,新生代又分為兩個區 Eden區Survial區,Survial又分為S0、S1區 默認各占8/10與1/10,1/10的空間

被說爛了的Java垃圾回收算法,我帶來了最“清新脫俗”的詳細圖解

?年輕代 老年代 堆空間結構

為什么要這么設計呢?為什么要分那么多不同的內存區域干嘛?這是由對象的生命周期特征、與各類垃圾回收算法的優缺點所決定的,這正式垃圾回收器設計的理論基礎。經過統計分析,大多數應用程序對象生命周期符合兩個特征:

垃圾回收的理論基礎

  • 絕大多數的對象都是“朝生夕滅”的,既創建不久即可消亡;
  • 熬過越多此垃圾回收過程的對象就越難以消亡;

一塊獨立的內存區域只能使用一種回收算法,根據對象生命周期特征,將其劃分到不同的區域,再對特定區域使用特定的垃圾回收算法,只有這樣才能將垃圾算法的優點發揮到極致,這種組合的垃圾回收算法叫:分代垃圾算法。。比如:在新生代使用標記-復制算法,在老年代使用標記-整理算法。

五、堆內存回收過程詳解

我們分析了如何判斷對象是否可回收,還有3中基礎的垃圾回收算法,以及年輕代、老年代的內存區域劃分與原因。接下來我們就一步一步來分析堆內存的回收流程。

5.1 內存初始狀態

假設在第一垃圾回收之前,內存中的狀態如圖所示Eden區有2個存活對象,3個垃圾對象,內存的可用區域已經所剩無幾,Survivor區因為還沒有進行任何MinorGC所以是空的,有1個大對象直接分配到了老年代,

被說爛了的Java垃圾回收算法,我帶來了最“清新脫俗”的詳細圖解

垃圾回收初始狀態

5.2 第1次執行MinorGC后狀態

當新的對象分配到Eden區,發現內存空間不夠,于是觸發第一次MinorGC,垃圾回收器首先將Edne區中的兩個存活對象復制到S0區,然后在清空Eden區的空間,如下圖:

被說爛了的Java垃圾回收算法,我帶來了最“清新脫俗”的詳細圖解

?第一次MinorGC內存狀態

5.3 程序運行一段時間后狀態

經過第1次MinorGC程序再運行一段時間后,堆內存狀態如下:Eden區又產生了大量的對象,并且大部分對象都可回收狀態,這也符合對象“朝生夕滅”的特征,S0區中也有1個對象可以回收,S1與老年代沒有變化,在這種狀態下,如果新對象分配再次觸發MinorGC會發生什么呢?

被說爛了的Java垃圾回收算法,我帶來了最“清新脫俗”的詳細圖解

?程序運行一度時間后的狀態

5.4 執行第2次MinorGC后狀態

新對象分配Eden區空間不足,又觸發了第二次MinorGC,第二次MinorGC與第一次GC時在Eden區的操作是一樣的:將Eden區存活的對象復制到S1區,然后在清空整個Eden區,同時也將S0區存活的對象復制到S1區并將對象的年齡加1,再清空S0區,GC后的狀態如下圖所示:

被說爛了的Java垃圾回收算法,我帶來了最“清新脫俗”的詳細圖解

?執行第二次MinorGC后狀態

5.5 第2MinorGC程序運行一段時間后狀態

經過第二MinorGC后程序又運行了一段時間,Eden區中有生成了很多對象,S1區也有一個對象可回收。

被說爛了的Java垃圾回收算法,我帶來了最“清新脫俗”的詳細圖解

第二MinorGC程序運行一段時間后狀態

5.6 第15MinorGC后內存狀態

在接下來的每次MinorGC時,都是第二次一樣,從Eden區和survivor非空白區移動存活對象到survivor區中空白區域,并清空這兩個區域內存空間,存活對象每此從survivor兩個區域移動一次,對象年齡加1,下圖表示經過了15次MinorGC后的堆內存狀態。

被說爛了的Java垃圾回收算法,我帶來了最“清新脫俗”的詳細圖解

?經過15次MinorGC后的內存狀態

對于年輕代區域的內存收集,使用的是標記-復制算法,只是為了減少復制算法空白區域的內存浪費,并不是將內存一份為二,而是巧妙的將內存分為三個區域,預留的空白區域只占整個年輕代區域的1/10。

5.7 對象如何進入老年代

以上是年輕代的分配與回收問題,那對象如何進入老年代呢?個人認為對象進入老年代,可以分為2種類型6種情況。

被說爛了的Java垃圾回收算法,我帶來了最“清新脫俗”的詳細圖解

?對象晉升入老年代

第一種類型--直接分配:對象創建時直接分配到老年代具體分為3種情況。

  • 超過虛擬機PretenureSizeThreshold參數設置大小的對象,該參數的默認值是0,也就是說任何大小的對象都會先分配到Eden區。
  • 超過Eden大小的對象
  • 如果新生代分配失敗,一個大數組或者大字符串

第二種類型--從年輕代晉升:從年輕代空間晉升到老年代也可分為3種情況。

  • 新生代分配擔保,在執行MinorGC時要將Eden區存活的對象復制到Survivor區,但是Survivor區默認空間是只有新生代的2/10,實際使用的只有1/10,當Survivor區內存不夠所有存活對象分配時,就需要將Survivor無法容納的對象分配到老年代去,這種機制就叫分配擔保。
  • 對象年齡超過虛擬機MaxTenuringThreshold的設置值,最大為15,
  • Survivor空間中相同年齡所有對象大小的總和大于Survivor空間的一半(TargetSurvivorRatio),年齡大于或等于該年齡的對象直接進入老年代。

內存分配擔保機制

在執行MinorGC時要將Eden區存活的對象復制到Survivor區,但是Survivor區默認空間是只有新生代的2/10,實際使用的只有1/10,當Survivor區內存不夠所有存活對象分配時,就需要Survivor無法容納將對象分配到老年代空間中,這種機制就叫分配擔保,但是,老年代的空間也是有限的,如果老年代中空間也不夠的話,那只能乖乖的執行一次FullGC了。

5.8 老年代回收算法-FullGC

當有對象要進入老年代,而老年代空間又不足時就會觸發FullGC,當然,反過來說觸發FullGC的條件不僅僅只是老年代空間不足,FullGC使用的算法是上面說的標記-整理算法。

被說爛了的Java垃圾回收算法,我帶來了最“清新脫俗”的詳細圖解

?完整堆內存回收過程

六、總結

判斷對象是否可以回收是垃圾回收的基礎與前提,通過可達性分析從GCRoots開始進行"順藤摸瓜"找到不可達對象(可回收)。

對象生命周期的特征"朝生夕滅"與"越戰越強"是垃圾回收算法的理論基礎。

基礎的垃圾回收算法有3種分別是 標記-清除算法、標記-負責算法、標記整理算法,都有各自的適應場合與優缺點。

分代垃圾算法根據對象生命周期的特征,將其劃分到不同的區域,從而使用最適合的垃圾算法來進行優化。

在JDK8默認的配置下使用 新生代,老年代的垃圾回收策略,新生代區域使用標記-復制算法,老年代區域使用標記-整理算法。

作者:攀巖飛魚

原文鏈接:https://xie.infoq.cn/article/9d4830f6c0c1e2df0753f9858

分享到:
標簽:回收 垃圾 Java
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定