Full GC回收詳解


在面試中我們會經常被問到full Gc相關的問題,比如什么情況下會發生full gc,如何去排查頻繁發生full Gc的問題等。要想輕松自如的回答這些問題,我們就必須充分的去理解gc的觸發條件,gc回收的內容,以及gc具體的執行過程。掌握了這3個要點,full gc相關的問題就易如反掌了。

一、gc的定義

GC,即就是Java垃圾回收機制。目前主流的JVM(HotSpot)采用的是分代收集算法。與C++不同的是,Java采用的是類似於樹形結構的可達性分析法來判斷對象是否還存在引用。即:從gcroot開始,把所有可以搜索得到的對象標記為存活對象。

二、gc的基礎知識准備

要了解GC的觸發條件,就要先對 JVM的內存結構有一定的了解。我們通常所說的GC主要是針對運行的數據區的。作為程序員要關注的區域主要有5塊,分別是方法區(Method Area),Java棧(Java stack),本地方法棧(Native Method Stack),堆(Heap),程序計數器(Program Counter Register)。實際jvm在管理內存的時候,比這個分的更細致,只不過做應用程序開發,我們只需要關注這5塊就可以了。

堆(Heap),是Jvm管理的內存中最大的一塊。程序的主要數據也都是存放在堆內存中的,這一塊區域被所有的線程所共享,通常出現線程安全問題的一般都是這個區域的數據出現的問題。

方法區(Method Area),與Heap一樣,也是各個線程共享的內存域,這塊區域主要是用來存儲類加載器加載的類信息,常量,靜態變量,通俗的講就是編譯后的class文件信息。

Jvm棧,與程序計數器一樣,它是每個線程私有的,它的生命周期與線程相同。虛擬機棧描述的是Java方法執行的內存模型:每個方法被執行的時候都會同時創建一個棧幀(Stack Frame)用於存儲局部變量表、操作棧、動態鏈接、方法出口等信息。每一個方法被調用直至執行完成的過程,就對應着一個棧幀在虛擬機棧中從入棧到出棧的過程。

本地方法棧(Native Method Stacks),本地方法棧(Native Method Stacks)與虛擬機棧所發揮的作用是非常相似的,其區別不過是虛擬機棧為虛擬機執行Java方法(也就是字節碼)服務,而本地方法棧則是為虛擬機使用到的Native方法服務。

程序計數器,個人感覺的他就是為多線程准備的,程序計數器是每個線程獨有的,所以是線程安全的。它主要用於記錄每個線程的執行情況。

通常我們所說的gc主要是針對java heap這塊區域的。下面來了解一下heap區。

從圖中我們可以看出jvm heap區域是分代的,分為年輕代,老年代和持久代。 JVM的堆區對象分配的一般規則:

  1. 對象優先在Eden區分配

  2. 大對象直接進入老年代(-XX:PretenureSizeThreshold=3145728 這個參數來定義多大的對象直接進入老年代)

  3. 長期存活的對象將進入老年代(在JDK8中測試,-XX:MaxTenuringThreshold=1的閥值設定根本沒用)

  4. 動態對象年齡判定(虛擬機並不會永遠地要求對象的年齡都必須達到MaxTenuringThreshold才能晉升老年代,如果Survivor空間中相同年齡的所有對象的大小總和大於Survivor的一半,年齡大於或等於該年齡的對象就可以直接進入老年代)

  5. 空間分配擔保

  . 只要老年代的連續空間大於(新生代所有對象的總大小或者歷次晉升的平均大小)就會進行minor GC,否則會進行full GC

三、gc的觸發條件

充分了解了jvm的內存結構之后,下面我們就來說說什么情況下會觸發gc。觸發full gc的情況主要有這幾種:

(1)System.gc()方法的調用。此方法的調用是建議JVM進行Full GC,雖然只是建議而非一定,但很多情況下它會觸發 Full GC,從而增加Full GC的頻率,也即增加了間歇性停頓的次數。強烈影響系建議能不使用此方法就別使用,讓虛擬機自己去管理它的內存,可通過通過-XX:+ DisableExplicitGC來禁止RMI(Java遠程方法調用)調用System.gc。

(2)舊生代空間不足。舊生代空間只有在新生代對象轉入及創建為大對象、大數組時才會出現不足的現象,當執行Full GC后空間仍然不足,則拋出錯誤:java.lang.OutOfMemoryError: Java heap space 。為避免以上兩種狀況引起的FullGC,調優時應盡量做到讓對象在Minor GC階段被回收、讓對象在新生代多存活一段時間及不要創建過大的對象及數組。

(3)Permanet Generation空間滿了。Permanet Generation中存放的為一些class的信息等,當系統中要加載的類、反射的類和調用的方法較多時,Permanet Generation可能會被占滿,在未配置為采用CMS GC的情況下會執行Full GC。如果經過Full GC仍然回收不了,那么JVM會拋出錯誤信息:java.lang.OutOfMemoryError: PermGen space 。為避免Perm Gen占滿造成Full GC現象,可采用的方法為增大Perm Gen空間或轉為使用CMS GC。

(4)通過Minor GC后進入老年代的平均大小大於老年代的可用內存。如果發現統計數據說之前Minor GC的平均晉升大小比目前old gen剩余的空間大,則不會觸發Minor GC而是轉為觸發full GC。

(5)由Eden區、From Space區向To Space區復制時,對象大小大於To Space可用內存,則把該對象轉存到老年代,且老年代的可用內存小於該對象大小

四、gc回收的內容

知道了gc觸發的條件之后,我們就能知道gc主要回收什么了?gc的主要作用是回收堆中的對象。通過可達性分析一個對象的引用是否存在,如果不存在,就可以被回收了。

五、gc的具體過程

那么,gc的是如何實現的,這個主要看是用的哪一種回收算法以及用的什么垃圾回收集了。回收算法主要有:

標記-清除復制算法標記-整理(Mark-Compat)算法分代收集(Generational Collection)算法這里針對不同的代,可以使用一些相對合適的算法。

新生代中,每次垃圾收集時都有大批對象死去,只有少量存活,就選用復制算法,只需要付出少量存活對象的復制成本就可以完成收集;

老年代中,其存活率較高、沒有額外空間對它進行分配擔保,就應該使用“標記-整理”或“標記-清理”算法進行回收。

常用的垃圾回收器:

  1、Serial收集器

  2、ParNew收集器

  3、Parallel Scavenge收集器

  4、CMS(Concurrent Mark Sweep)收集器

  5、G1(Garbage First)收集器(從JDK1.7 Update 14之后的HotSpot虛擬機正式提供了商用的G1收集器)關於垃圾回收器的使用,這里也有一個組合建議共大家參考:

 本文轉載:Java面試總結之Full GC

后續鏈接:Weblogic/WAS之Full GC監控與計算


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM