JVM垃圾回收(新手推薦)

提到JVM垃圾回收,總覺得離我們程序員有一定的距離。在JAVA中,那是系統(tǒng)自己干的事,我們關(guān)心那個干嘛?也就是說我們?yōu)槭裁匆獙W習這個東西,大家開開心心地敲代碼不好嗎?

還真的不好,一方面我覺得我們可以學習下JAVA語言設(shè)計上的一些思想,另一方面,在我們以后從事一些較為高級一點的開發(fā),尤其是性能調(diào)優(yōu)之類的,知道這些基礎(chǔ)知識就顯得很必要了。我打算從以下幾個方面開始進行簡單地說明。

GC如何知道哪些對象是垃圾對象?

GC不可能隨便指派說哪個對象是垃圾,要有一定的依據(jù)。常用的標記垃圾的算法有兩個:

引用計數(shù)算法

引用計數(shù)算法,就是每個對象有一個引用計數(shù)器,當該對象被引用的時候計數(shù)器加1,當引用失效的時候,計數(shù)器減1。

那么這么做有什么缺點嗎?

那就是當兩個對象相互引用的時候,這兩個對象都會無法釋放。

根搜索算法

從根對象開始,所有能被觸及的對象都可以認為是“存活的”對象,換句話說,就是“仍然使用的”對象。不能被觸及的對象,就會被認為是垃圾,需要回收。

根搜索算法(圖片來自于網(wǎng)絡(luò))
根搜索算法(圖片來自于網(wǎng)絡(luò))

那么什么對象可作為GC Roots呢?

  1. 虛擬機棧(棧幀中的本地變量表)中引用的對象;
  2. 方法區(qū)中類靜態(tài)屬性的引用;
  3. 方法區(qū)中常量引用的對象;
  4. 本地方法棧中JNI(Native方法)引用的對象。

什么是虛擬機棧?

虛擬機棧為Java方法服務。說的簡單點,就是我們平時所寫的Java方法,沒調(diào)用一個Java方法,就是入棧的過程,退出方法就是出棧的過程。每個Java方法對應于虛擬機棧中的一個棧幀。

什么是本地方法棧?

本地方法棧為native方法服務。

方法區(qū)是什么呢?

方法區(qū)與Java堆一樣,是各個線程共享的內(nèi)存區(qū)域,它用于存儲已被虛擬機加載的類信息,常量,靜態(tài)變量,即時編譯器編譯后的代碼等數(shù)據(jù)。可以看做堆的一個邏輯部分。

常用的垃圾回收算法有哪些?

看下圖,整幢大樓燈火通明,其中不排除一些辦公室沒人但還是燈亮著的情況,為了節(jié)約資源,我們需要關(guān)掉那些辦公室沒人的燈。那么怎么辦呢?

內(nèi)存啊
內(nèi)存啊

標記——清除算法

我從頂樓開始到一樓,一塊一塊辦公區(qū)域看,對沒人的區(qū)域進行關(guān)燈。將整個大樓看成內(nèi)存,燈亮著的區(qū)域表示有對象存在,燈滅著的表示空閑區(qū)域。我們一塊一塊區(qū)域檢查的這個過程就是標記的過程,關(guān)燈的操作就是清除的過程。這就是標記——清除算法。

標記——清除算法(圖片來自于網(wǎng)絡(luò))
標記——清除算法(圖片來自于網(wǎng)絡(luò))

弊端:

  1. 那就是費時費力,效率太低。
  2. 不連續(xù),不美觀(內(nèi)存碎片嚴重)。

復制回收算法

老板說了,浪費太嚴重了,到了晚上,我們對需要加班的同事進行統(tǒng)一安排。假設(shè)大樓共10層,只能使用15層或者610層(畢竟晚上加班的人不多)。比如現(xiàn)在使用的就是15樓,到了晚上要用燈了,需要加班的同事自己去610樓找位置,保安一聽樂了,再也不用一塊一塊區(qū)域關(guān)燈了,有需要的人都去610樓了,剩下的即便是燈亮著的辦公區(qū)域那也是沒人,讓我分別去15樓拉個總閘先(回收的過程)。

復制回收算法(圖片來自于網(wǎng)絡(luò))
復制回收算法(圖片來自于網(wǎng)絡(luò))

可以看到,在任意時刻只用到了內(nèi)存的一半。

弊端:

  1. 有需要的同事搬到6~10樓的過程,太麻煩。特別是需要加班的同事比較多的時候。(需要對有用的對象進行復制)。
  2. 整棟大樓只能用一半,哎(內(nèi)存使用率降低)。

優(yōu)點:

從外面看,我知道哪些地方有人,哪些地方?jīng)]人,方便了管理(內(nèi)存無碎片)。

標記——整理算法

下班后,保安大哥將空的辦公區(qū)域依次統(tǒng)計出來(標記的過程),需要加班的同事按照統(tǒng)計結(jié)果,依次搬到空閑的辦公區(qū)域。保安大哥知道,我只需要找到最后一個有人的區(qū)域,那么這塊區(qū)域之后肯定不會有人了,不用挨個檢查了,去拉后面的閘。

標記——整理算法(圖片來自于網(wǎng)絡(luò))
標記——整理算法(圖片來自于網(wǎng)絡(luò))

優(yōu)點:

  1. 內(nèi)存無碎片。
  2. 同時避免了當有用對象比較多的時候,復制回收算法的麻煩。

分代回收算法

JVM劃分
JVM劃分

新生代:

剛創(chuàng)建的對象都在新生代,新生代采用復制回收算法。新生代分為三個區(qū),一個Eden區(qū),一般兩個Survivor區(qū)。大部分對象在Eden區(qū)生成,當Eden區(qū)域滿時,將還存活的對象復制到其中一個Survivor區(qū)域,當這個Survivor區(qū)域滿時,將其中還存活的對象復制到第二個Survivor區(qū)域。那么當?shù)诙€Survivor區(qū)域滿時該怎么辦呢?那就是將第二個Survivor區(qū)域中由第一個Survivor區(qū)域復制過來的對象,復制到“老年代”中。

這個過程是有點繞,但是可以想象成面試過程中層層選拔的過程,能力越強的可以想象成生命周期越長的對象。

老年代:

這個區(qū)域中的對象都是在新生代中經(jīng)歷了層層回收后仍然存活的對象,這個區(qū)域采用標記整理的算法進行垃圾回收。

持久代:

持久代中用于存放一些靜態(tài)文件,static常亮,常量池等。這塊區(qū)域?qū)厥諞]有顯著影響。

什么時候會進行垃圾回收?

GC有兩種類型:Minor GC和Full GC。

Minor GC

當新對象生成,并且在Eden申請空間失敗時,就會觸發(fā)Minor GC,對Eden區(qū)域進行GC,清理非存活對象。

Full GC

對整個堆進行整理,所以比Minor要慢,所以盡可能地減少Full GC的次數(shù)。在對JVM調(diào)優(yōu)的過程中,很大一部分工作就是對于Full GC的調(diào)節(jié)。有如下原因可能導致Full GC:

  1. 老年代被寫滿;
  2. 持久代被寫滿;
  3. System.gc()被顯式調(diào)用。

參考資料:《深入理解Java虛擬機:JVM高級特性與最佳實踐(第二版)》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • 1.什么是垃圾回收? 垃圾回收(Garbage Collection)是Java虛擬機(JVM)垃圾回收器提供...
    簡欲明心閱讀 90,388評論 17 311
  • 作者:一字馬胡 轉(zhuǎn)載標志 【2017-11-12】 更新日志 日期更新內(nèi)容備注 2017-11-12新建文章初版 ...
    beneke閱讀 2,334評論 0 7
  • JVM架構(gòu) 當一個程序啟動之前,它的class會被類裝載器裝入方法區(qū)(Permanent區(qū)),執(zhí)行引擎讀取方法區(qū)的...
    cocohaifang閱讀 1,852評論 0 7
  • 1.一些概念 1.1.數(shù)據(jù)類型 Java虛擬機中,數(shù)據(jù)類型可以分為兩類:基本類型和引用類型。基本類型的變量保存原始...
    落落落落大大方方閱讀 4,830評論 4 86
  • 原文閱讀 前言 這段時間懈怠了,罪過! 最近看到有同事也開始用上了微信公眾號寫博客了,挺好的~給他們點贊,這博客我...
    碼農(nóng)戲碼閱讀 6,163評論 2 31

友情鏈接更多精彩內(nèi)容