觸發Full GC的時機

2022-05-08 07:06:13 字數 2934 閱讀 1598

由於full gc的耗時是minor gc的十倍左右,所以full gc的頻率設計得比minor gc低得多。現總結一下觸發full gc的情況。

在那些實現了cms的比較新的虛擬機器中,如果配置了-xx:+useconcmarkswapgc,則啟用cms**演算法,cms會周期性地檢查老年代的情況,每隔一定時間(預設2秒),就檢查是否需要對老年代進行一次cms**,判斷的依據如下:

1、如果沒有設定-xx:+usecmsinitiatingoccupancyonly,虛擬機會根據收集的資料決定是否觸發(建議線上環境帶上這個引數,不然會加大問題排查的難度)。

2、老年代使用率達到閾值cmsinitiatingoccupancyfraction,預設92%。

3、永久代的使用率達到閾值cmsinitiatingpermoccupancyfraction,預設92%,前提是開啟cmsclassunloadingenabled

4、新生代的晉公升擔保失敗。

參考:《**cms垃圾**機制,你值得擁有》

cms分為兩種模式,background和foreground,background採用concurrent remark模式,可以和使用者程序並行,而foreground則必須要stop the world(stw)。週期性的cms採用的是background的方式,而主動的gc則採用foreground方式。主動的gc肯定是full gc,反之則未必,因為full gc不是只在cms中存在的,並且full gc也可以是並行的full gc(區別於正常的full gc),採用並行的full gc在old gc階段走的是background式的cms,可參考寒泉子《jvm原始碼分析之systemgc完全解讀》一文。本文的重點也是full gc。

因為full gc所用的時間較長,為了充分發揮cms的優勢,通常都會配置-xx:+usecmsinitiatingoccupancyonly,讓cms週期性的以和使用者現場並行的方式進行垃圾**,這也是cms設計的初衷。

但是呢,因為cms採用標記-清理的方式進行gc,所以會產生碎片,時間久了,碎片就會很多,所以一般來說,進行了一段時間cms之後,如果開啟了usecmscompactatfullcollection(預設為true開啟),在foreground的時候就要採用一次壓縮,這時採用serial old或parallel old這些採用標記-整理演算法的gc方式(cms採用的是標記-清理演算法)進行**。具體多少次full gc (foreground cms)之後進行一次壓縮,取決於-xx:cmsfullgcsbeforecompact(預設為0)。原始碼如下:

*should_compact = usecmscompactatfullcollection && 

((_full_gcs_since_conc_gc >= cmsfullgcsbeforecompaction)

|| gccause::is_user_requested_gc(gch->gc_cause())

|| gch->incremental_collection_will_fail(true /*consult_young */)

);

從原始碼可以看出,除了達到一定次數之外,如果使用者呼叫了system.gc()以及發生了promotion failed,也會進行一次壓縮。同時也可以看出,foreground不一定會採用壓縮,所以那些說foreground就是mark swap compact(msc)的是不對的。

但是週期性的cms(background)只會**老年代,除了週期性的進行gc之外,還有一些緊急情況,需要主動觸發gc(foreground),主動觸發的gc會連帶一次minor gc,所以也稱為full gc。主動觸發的gc是會暫停所有使用者現場的,俗稱stop the world(stw)。

在那些沒有實現cms的老虛擬機器或者沒有開啟cms的虛擬機器中,每一次old gc都是full gc,且會stw,當然因為除了cms之外,其他的老年代**演算法都是採用標記-整理的方式,所以肯定也是壓縮的,。

如果正在進行cms**,又觸發了一次full gc,則full gc會搶占**執行機會,停止cms,採用serial old或parallel old這些採用標記-整理演算法的gc方式(cms採用的是標記-清理演算法)進行full gc。

下面是一些會觸發full gc的情況

在沒有開啟disableexplicitgc的情況下,雖然只是建議,但是很多情況下,都會呼叫full gc的,比如在原本應進行cms的時候。system.gc()一般都是用在要釋放堆外記憶體的時候使用。

這種情況通常是物件要晉公升到老年代中時,發現老年代的記憶體不足了,所以要引發一次full gc。物件的晉公升分為正常晉公升和提前晉公升。

有些虛擬機器把方法區也放到堆中管理,當載入的類太多時,永生區記憶體不足需要**,也會觸發full gc

在minor gc時發現to去的記憶體不足,則將eden區和from區的記憶體全部晉公升到老年區,清空新生代。但是如果此時老年區記憶體不足,則會冒險失敗,冒險失敗之後,物件仍然留在新生代(此時的eden區和from區都接近99%),然後出發一次full gc,這樣便於下次如果還有冒險,可以增加冒險成功的機率。

在minor gc之前,虛擬機會檢查老年代剩餘連續空間是否大餘新生代所有物件總大小,如果大餘,則說明minor gc絕對安全;如果小於,則會檢查handlepromotionfailure設定是否擔保失敗,如果不擔保,則在minor gc之前進行一次full gc;如果擔保,則再檢查歷年平均晉公升物件的大小是否大餘老年代剩餘連續空間,如果大餘,則不冒險,在minor gc之前進行一次full gc;如果小於,則冒險,進入情況4。

如果直接要分配乙個大物件,並且這個大物件的大小超過eden區的一半,這個物件就會直接分配在老年代,此時如果老年代空間不足,出發一次full gc,而不出發minor gc。但是需要注意的是,如果分配的是tlab而不是真正的大物件,那麼不會導致full gc,而是調整tlab的大小。

這屬於強制讓虛擬機器執行一次full gc。

PHP 常用魔術方法的觸發時機

1 autoload 當程式例項化某個類,而該類沒有在當前檔案中被引入。此時會觸發執行 autoload 程式希望通過該方法,自動引入這個類檔案。該方法有乙個引數,即就是那個忘記引入的類的名稱。autoload 方法的工作原理是什麼?當程式執行到例項化某個類的時候,如果在例項化前沒有引入這個類檔案,...

事件的觸發時機及先後順序

開啟窗體 open 窗體 load 窗體 resize 窗體 activate 窗體 current 窗體 enter 第乙個擁有焦點的控制項 gotfocus 第乙個擁有焦點的控制項 關閉窗體 exit 控制項 lostfocus 控制項 unload 窗體 deactivate 窗體 close...

PB 事件的觸發時機及先後順序

事件的觸發時機及先後順序 開啟窗體 open 窗體 load 窗體 resize 窗體 activate 窗體 current 窗體 enter 第乙個擁有焦點的控制項 gotfocus 第乙個擁有焦點的控制項 關閉窗體 exit 控制項 lostfocus 控制項 unload 窗體 deacti...