頻道欄目
首頁 > 資訊 > 其他綜合 > 正文

JVM 垃圾回收機制主要原理

16-10-05        來源:[db:作者]  
收藏   我要投稿

對于垃圾JVM的垃圾回收機制這里我們稱為GC,眾所周知,java語言不需要像c++那樣需要自己申請內存,自己釋放內存,這些都是JVM幫我們做好了的,但是對于一名java程序員,想要更近自己的水平更上一層樓,就要去了解GC的工作原理,根據原理才能寫出更好的更優的程序,這里我們先初步講解一下GC的工作原理


首先我們在講解之前我們需要了解一下JVM內存運行時數據區的三個重要的地方

堆(heap) : 他是最大的一塊區域,用于存放對象實例和數組,是全局共享的. 棧(stack) : 全稱為虛擬機棧,主要存儲基本數據類型,以及對象的引用,私有線程 方法區(Method Area) : 在class被加載后的一些信息 如常量,靜態常量這些被放在這里,在Hotspot里面我們將它稱之為永生代

關于具體結構可以用下面這張圖來對內存運行時數據區有一個大致的概括
這里寫圖片描述

堆(heap):,前面已經說了他是最大的,也是最重要的一塊區域,這里也稱為邏輯堆,主要用來存放對象實例與數組,對于所有的線程來說他是共享的,對于Heap堆區是動態分配內存的,所以空間大小和生命周期都不是明確的,而GC的主要作用就是自動釋放邏輯堆里實例對象所占的內存,而在邏輯堆中還分為新生代與老年代,用來區分對象的存活時間,在新生代中還被細致的分為 Eden SurvivorFrom以及SurvivorTo這三部分.


方法區(Method Area):方法區主要存儲(類加載器)ClassLoader加載的類信息,在這里我們可以理解為已經編譯好的代碼儲存區,所以存儲包括類的元數據,常量池,字段,靜態變量與方法內的局部變量以及編譯好的字節碼,等等

棧(stack):在每一個對象被創建的時候,在堆棧區都有一個對他的引用,在這里我們可以這樣理解。

Object obj = new Object();

上面的代碼左邊的Object obj 等于在堆棧區申請了一個內存,這里也就是對類的引用了,而 new Object()則是生成了一個實例,=則是 將對象的內容則可通過obj進行訪問,在Java里都是通過引用來操縱對象的。

pc寄存器(PC Regesiter): 在多線程中,系統需要給每一個線程 分配一個進程編號,這個時候才會需要到寄存器。


好了 基本的都介紹完了,現在來進入正題 :

我們知道對象的實例是存在于邏輯堆中,而GC在邏輯堆是怎樣運行的呢,下面我們看下邏輯堆的具體結構
這里寫圖片描述
就像上面的圖可以看出 邏輯堆分為 年輕代與年老代,對于非堆內存這里先不講解,而年輕代則被分為 eden survivor1 survivor2 ,對于一個新被實例化的對象都是存在于年輕代中的eden區,至于為什么,下面會講到,eden中文名為伊甸園,按照GC的運行機制,會回收掉已經死掉的對象,而對象一般都是在年輕代就會死去,所以年輕代比老年代需要更頻繁的GC清理,下面針對年輕代與老年代的回收機制有不同的講解

年輕代 :

在年輕代中jvm使用的是Mark-copy算法,就像算法名字說的那樣有兩個步驟,第一是標記(Mark) 第二是copy(復制),Mark主要用于標記出還活著的實例,然后清除掉沒有被標記的實例,釋放內存,然后Copy部分則是將還活著的實例根據年齡拷貝到不同的年齡代,而jvm又是根據什么來區分年齡代,和實例存活與不存活的呢? 下面將對這個過程進行講解


對于標記 與區分年齡代的技術 我們一般都是用到的都是引用計數器,在每一個對象中都含有引用計數器,都有引用指向對象的時候 引用計數器就會加1,不在被引用 計數器 減 1,對與垃圾回收的策略則是標記所有活著的實例,將沒有被標記的實例全部回收 釋放內存,


對于靜態,我們都知道靜態方法與靜態變量是不會產生實例的,直接通過類的引用,使用 ClassLoader進行加載的類數據如前面所說是不存在邏輯堆里面的,直接存在于永生代里面也就是 方法區里面,這個類一旦被清除掉里面所有的靜態變量都會被清除

當我們在 Object obj 的時候 向邏輯堆中的 Eden區域 申請內存,當Eden區域的內存不足的時候,這個時候會觸發GC這個時候稱gc為小型垃圾回收,每個實例都有一個獨有的年齡,每個引用被經歷過一次GC后就會年齡加一,同時就會將沒有被清理掉的對象全都copy到上圖的survivor1區域,如圖1所示:
這里寫圖片描述
當第二次GC執行的時候就會使用Mark算法找到存活的對象,然后將他們的年齡加1,并且將他們拷貝到survivor2區域,然后執行GC,這樣就可以實現survivor1 與 survivor2 兩個一樣大的區域進行交替使用,當對象的年齡足夠大的時候,對象就會被移動到老年代,這里移動到老年代的標準由JVM的參數所決定

年老代 :

當GC被觸發的時候 eden的對象會轉到 survivor1 然后再次就會轉到 survivor2 ,當survivor1的對象太大了 survivor2的區域無法容納得部分就會轉到Tenured的區域,當Tenured的區域也容不下的時候就會自動移動到年老代,在移動年老代的時候會先觸發年老代上面的GC然后在將Tenured容納不下的對象放入年老代,對于年老代的GC算法與年輕代的Mrak-copy算法有很大不同

年老代的GC算法在jdk 1.7 中分為五種,

Serial GC
Parallel GC
Parallel Old GC(Parallel Compacting GC)
Concurrent Mark & Sweep GC (or “CMS”)
Garbage First (G1) GC

在這里我只講解兩種Parallel Scavenge 與 Concurrent Mark sweeps 對與這兩種接下來會進行簡單的講解

Parallel Scavenge :

在這里我們簡稱他為PS算法,PS算法執行的是 Mark-compact算法的過程 ,并且是用多線程進行執行這樣提高了執行效率,這里的Mrak還是與之前的年輕代的Mark原理是一樣的,但是Compat算法則是將年老代的對象進行碎片化的整理,并且年老代是沒有像年輕代的那樣有survivor1 與 survivor2來將殘留的對象全部copy過去,考慮到年老代的對象比較多,所以就需要進行碎片化整理如下圖:
這里寫圖片描述

Concurrent Mark sweeps:

我們簡稱他為 CMS 算法,對與cms算法,我們先需要了解一個概念 Stop the world,對于Stop the world,不管選擇哪種GC算法,stop-the-world都是不可避免的。Stop-the-world意味著從應用中停下來并進入到GC執行過程中去。一旦Stop-the-world發生,除了GC所需的線程外,其他線程都將停止工作,中斷了的線程直到GC任務結束才繼續它們的任務。GC調優通常就是為了改善stop-the-world的時間。在CMS GC開始時的初始標記(initial mark)比較簡單,只有靠近類加載器的存活對象會被標記,因此停頓時間(stop-the-world)比較短暫。在并發標記(concurrent mark)階段,由剛被確認和標記過的存活對象所關聯的對象將被會跟蹤和檢測存活狀態。此步驟的不同之處在于有多個線程并行處理此過程。在重標記(remark)階段,由并發標記所關聯的新增或中止的對象瘵被會檢測。在最后的并發清理(concurrent sweep)階段,垃圾回收過程被真正執行。在垃圾回收執行過程中,其他線程依然在執行。得益于CMS GC的執行方式,在GC期間系統中斷時間非常短暫。CMS GC也被稱為低延遲GC,

關于GC的原理就講到這里了,這篇博客只講解了最基本的GC 接下來要學習的還有更多,加油吧

相關TAG標簽
上一篇:臺積電:絕大多數7nm客戶都會轉向6nm_IT新聞_博客園
下一篇:最后一頁
相關文章
圖文推薦

關于我們 | 聯系我們 | 廣告服務 | 投資合作 | 版權申明 | 在線幫助 | 網站地圖 | 作品發布 | Vip技術培訓 | 舉報中心

版權所有: 紅黑聯盟--致力于做實用的IT技術學習網站

美女MM131爽爽爽毛片