JVM垃圾回收機制(GC)

JVM垃圾回收機制(GC)

引入:我們都知道,棧內存中方法運行完畢後會有彈棧的操作,不會產生垃圾,而堆內存中卻沒有這種操作,當堆內存中很多無用的成員變量、對象等等積壓到一定程度時,就會發生堆內存溢出的一個錯誤OutOfMemoryError (Java heap space)堆內存溢出 ,雖然說堆內存的大小是可以調節的,但是它還是解決不了根本問題。那麼爲了避免這種情況的發生,出現了垃圾回收機制,也就是我們所說的GC。

堆內存的結構

堆內存邏輯上是分爲三個部分:新生代、養老代、永久代(jdk1.7以後我們稱永久代爲元空間)。
在這裏插入圖片描述
但是實際上負責存儲的只有:新生代、養老代。
在這裏插入圖片描述

回收機制介紹

對象在伊甸區(Eden)被new出來,當伊甸區滿了以後還需要創建對象,這時候JVM會對伊甸區進行垃圾回收(YGC也叫輕GC),將伊甸區中的沒有被其他對象所引用的對象進行銷燬(finalize()方法用於銷燬對象的)。然後將伊甸區中存活的對象移動到倖存0區,並且該對象年齡爲1,當伊甸區再滿了之後會對伊甸區和倖存0區的對象進行GC,然後會將伊甸區和倖存0區存活的對象移動到倖存1區,如果當前存活的對象GC前是倖存區的,那麼他們的年齡+1,就這樣GC一次交換一次年齡增長一次,如果有對象經過了15次GC依然存活(15歲),會被轉移到養老區(Old),當養老區滿了之後也會進行垃圾回收(Full GC也叫重GC),對養老區進行垃圾清理,當最後沒有可清理的垃圾時且新生代、養老代都滿了之後,會報一個異常:OutOfMemoryError (Java heap space)

異常原因:
代碼中創建了大量的對象,且長時間不能被回收,導致創建新對象出現堆內存溢出。

關於新生代GC之後有交換,誰空誰是To的圖解

在這裏插入圖片描述
文字解釋:第一次GC會把存活的對象存入倖存0區(當前的Form區),第二次GC會把所有存活的對象存入倖存1區(當前From區),第三次GC會把所有存活的對象存入倖存0區(當前From區),你會發現每次有對象的哪個區就是From區,沒有對象的那個區就是To區。
這樣就驗證了上面那句:GC之後有交換,誰空誰是To

解讀GC日誌

從百度上扒拉了兩個GC圖,希望可以幫到你。
簡稱Young GC 爲 YGC
簡稱Full GC 爲 FGC
Young GC
在這裏插入圖片描述
Full GC在這裏插入圖片描述

GC算法

  • 引用計數法(已經不用了)
    缺點:老算法,比較消耗內存,比較難處理循環引用。

  • 複製回收算法:(GC 90%用的都是這個,這個算法一般用在YGC就是我們的新生代)
    優點:不會產生內存碎片,效率高。
    缺點:浪費內存空間。
    最經典的體現在這句話:GC之後有交換,誰空誰是To。 裏面所提到的交換其實就是在一次GC之後,把剩餘存活的對象複製到下一個倖存區,從而就導致了必須要有兩個倖存區的概念 (倖存0區和倖存1區) 所以就是比較消耗內存空間。因爲是直接複製的所以比較省時,不會產生內存碎片。

  • 標記清除算法:(用於FGC,一般用在老年代)
    優點:節約空間
    缺點:掃描標記耗時,併產生內存碎片,效率不高。
    先標記那些對象是需要回收的,標記完成後,對帶有標記的對象進行統一的回收,因爲分爲了標記和回收兩步,所以效率較低,同時對象與對象之間會有內存碎片產生。

  • 標記清除壓縮算法:(用於老年代)
    優點:更加節約空間,不會產生內存碎片
    缺點:與標記清除算法相比多了壓縮的這一步,所以耗時更長,效率不高。
    先標記那些對象是需要回收的,標記完成後,對帶有標記的對象進行統一的回收,然後在對存活的對象進行壓縮規整,分爲了標記、清除、壓縮三步,多以效率更低一些,但是由於已經壓縮規整了所以不會產生內存碎片。

總結: 那個算法合適我們就用那個算法
一般新生代用:複製算法(效率高,耗內存空間)
一般老年代用:標記清除與壓縮的結合(省內存空間,但是效率低)

如果這篇文章對您有幫助,那麼請留下您的足跡吧…!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章