上一篇總結GC的基礎算法,各種GC收集器的基本原理,還是比較粗粒度的概念。這篇會整理一些GC的常見概念,理解了這些概念,相信對GC有更加深入的理解
1. 什么時候會觸發(fā)Minor GC?
- Eden區(qū)域滿了,或者新創(chuàng)建的對象大小 > Eden所??臻g
- CMS設置了CMSScavengeBeforeRemark參數(shù),這樣在CMS的Remark之前會先做一次Minor GC來清理新生代,加速之后的Remark的速度。這樣整體的stop-the world時間反而斷
- Full GC的時候會先觸發(fā)Minor GC
2. 什么時候會觸發(fā)Full GC?
- Minor GC后存活的對象晉升到老年代時由于悲觀策略的原因,有兩種情況會觸發(fā)Full GC, 1種是之前每次晉升的對象的平均大小 > 老年代剩余空間
- 1種是Minor GC后存活的對象超過了老年代剩余空間。這兩種情況都是因為老年代會為新生代對象的晉升提供擔保,而每次晉升的對象的大小是無法預測的,所以只能基于統(tǒng)計,1個是基于歷史平均水平,一個是基于下一次可能要晉升的最大水平。這兩種情況都是屬于promotion failure
- CMS失敗,發(fā)生concurrent mode failure會引起Full GC,這種情況下會使用Serial Old收集器,是單線程的,對GC的影響很大。concurrent mode failure產生的原因是老年代剩余的空間不夠,導致了和gc線程并發(fā)執(zhí)行的用戶線程創(chuàng)建的大對象(由PretenureSizeThreshold控制新生代直接晉升老年代的對象size閥值)不能進入到老年代,只要stop the world來暫停用戶線程,執(zhí)行GC清理。可以通過設置CMSInitiatingOccupancyFraction預留合適的CMS執(zhí)行時剩余的空間
- 新生代直接晉升到老年代的大對象超過了老年代的剩余空間,引發(fā)Full GC。注意于promotion failure的區(qū)別,promotion failure指的是Minor GC后發(fā)生的擔保失敗
- Perm永久代空間不足會觸發(fā)Full GC,可以讓CMS清理永久代的空間。設置CMSClassUnloadingEnabled即可
- System.gc()引起的Full GC,可以設置DisableExplicitGC來禁止調用System.gc引發(fā)Full GC
3. CMS不等于Full GC,很多人會認為CMS肯定會引發(fā)Minor GC。CMS是針對老年代的GC策略,原則上它不會去清理新生代,只有設置CMSScavengeBeforeRemark優(yōu)化時,或者是concurrent mode failure的時候才會去做Minor GC
4. 什么情況下新生代對象會晉升到老年代?
- 當對象大小超過了PretenureSizeThreshold設置的對象大小閥值時,對象直接在老年代分配空間
- 當age從1開始的對象大小累計超過了Survivor區(qū)域的1/2(TargetSurvivorRatio所定義)時,會計算一個Thenuring Threshold,超過這個年齡的新生代對象會進入到老年代,即使這時候新生代還有很多的空間。注意MaxTenuringThreshold只是設置了最大的Thenuring Threshold,不是說只有大于Max Tenuring Threshold才會進入到老年代,而是只要超過了計算出來的Tenuring Threshold就會進入老年代,MaxTenuringThreshold規(guī)定了Tenuring Threshold的最大值而已。Tenuring Threshold這個值在每一輪GC后都會動態(tài)計算,它與TargetSurvivorRatio以及Survivor區(qū)的大小有關系,TargetSurivivor默認是50即Survivor的1/2, 會計算出一個Desired Survivor Size,當age從1開始的對象大小累計超過了這個Desired Survivor Size,那么這個age就是Tenuring Threshold的值
5. 一旦對象進入了老年代,那么只有觸發(fā)CMS(只針對CMS而言)或者Full GC的時候才能被清除
6. Heap什么時候會發(fā)生OOM?
- 當花在GC的時間超過了GCTimeLimit,這個值默認是98%
- 當GC后的容量小于GCHeapFreeLimit,這個值默認是2%
7. 什么是剩余空間不夠?
剩余空間不夠不是說整體的空間不夠分配某個對象,而是說連續(xù)的空間不夠分配給某個對象。所以一旦內存碎片大多就可能發(fā)生剩余空間不夠的問題,所以CMS這種收集器,需要在標記-清除幾次之后進行壓縮,進行優(yōu)化。CMSFullGCsBeforeCompaction可以設置進行幾次清除之后進行壓縮
8. Full GC的次數(shù)說的是stop the world的次數(shù),所以一次CMS至少會讓Full GC的次數(shù)+2,因為CMS Initial mark和remark都會stop the world,記做2次。而CMS可能失敗再引發(fā)一次Full GC
9. JMI默認會一個小時調用一次System.gc()清理緩存,所以可以DisableExplicitGC,也可以設置sun.rmi.dgc.client.gcInterval和sun.rmi.dgc.server.gcInterval參數(shù)來規(guī)定JMI清理的時間
10. 對于性能調優(yōu)來說,應該理解對于給定的硬件,給定的算法(垃圾收集器),單個/多個線程單位時間內能夠回收的空間是接近一個常量的。如果想要縮短GC的時候,就要考慮是否要相應調小空間
11. CMS收集器會了減少stop the world的時間,讓GC線程和業(yè)務線程并發(fā),這樣也就相對拉長了CMS收集器單次GC的時間
12. 盡可能地讓對象停留在新生代,因為新生代采用了復制算法,相對收回得更快,而且Minor GC的次數(shù)肯定比Full GC多,那么對象在新生代被清除的更能性會更高。而對象一旦進入到老年代,那么只有Full GC時才會回收,對象在整個系統(tǒng)停留的時間就會很長,很可能創(chuàng)建的它的線程早就死了,而它還活著
13. 為了盡可能讓對象停留在新生代,就要注意設置Survivor區(qū)域的大小,因為它直接和對象是否進入老年代相關。之前就遇到過這種情況,明明新生代還有很大的空間,但是每次Minor GC后總是有對象進入到了老年代。后來發(fā)現(xiàn)由于Survivor太小,導致Tenuring Threshold為1,意思是年齡為1的對象大小超過了Survivor / 2(可通過TargetSurvivorRatio來調節(jié),默認是50,即1/2),年齡只要超過1的對象這時候就要直接進入老年代了。而進入老年代,對象就只有在Full GC的時候才會被清除。而如果調大了Survivor空間,讓對象對象盡量接近Max Tenuring Threshold時才進入到老年代,這時候會大大減少老年代的對象大小,并且讓對象在新生代停留時間變長,提高了它們被快速清理出系統(tǒng)的概率。
本站僅提供存儲服務,所有內容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內容,請
點擊舉報。