新聞中心
概述

本周有個(gè)同事過來咨詢一個(gè)比較詭異的gc問題,大概現(xiàn)象是,系統(tǒng)一直在做cms gc,但是老生代一直不降下去,但是執(zhí)行一次jmap -histo:live之后,也就是主動(dòng)觸發(fā)一次full gc之后,通過jstat -gcutil來看老生代一下就降下去了,初看下理論上不太可能,因?yàn)閒ull gc也會(huì)對old做回收,于是我要同事針對他們的場景寫了一個(gè)簡單的demo出來,然后果然還真能重現(xiàn),不過他的demo設(shè)置的Heap有32G,于是我通過慢慢調(diào)整,最終在很小的內(nèi)存下也能重現(xiàn)出來。
Demo
測試代碼如下:
正如我上面注釋里寫的JVM參數(shù),控制新生代200M,老生代300M,老生代使用率達(dá)到90%的時(shí)候觸發(fā)CMS GC,大家可以跑跑看,這種情況下會(huì)發(fā)現(xiàn)不斷做CMS GC,但是老生代就是不降下去,但是只要你主動(dòng)觸發(fā)一次Full GC,老生代立馬就會(huì)回收。
當(dāng)allocateMemory方法執(zhí)行完之后,期待的結(jié)果是gc之后List及里面的byte數(shù)組都應(yīng)該被回收掉,可是事實(shí)并不是這樣的。
初步定位
這段代碼非常簡單,我翻來覆去地看著這段代碼,視圖想改變點(diǎn)什么,能讓問題出現(xiàn)峰回路轉(zhuǎn),我不斷地控制for循環(huán)的次數(shù)和每次分配的內(nèi)存大小,最終我將目標(biāo)轉(zhuǎn)移到那個(gè)ArrayList上,List里有個(gè)數(shù)組,在add過程中如果發(fā)現(xiàn)數(shù)組不夠了,于是會(huì)進(jìn)行擴(kuò)容,那擴(kuò)容就是創(chuàng)建新的數(shù)組,將老的對象放到新數(shù)組里,那我試想要是不做擴(kuò)容會(huì)不會(huì)有問題?于是我開始調(diào)整ArrayList的初始化大小,當(dāng)我調(diào)到一定大小,保證在add過程中不會(huì)做擴(kuò)容,問題真出現(xiàn)了反轉(zhuǎn),居然能正?;厥樟?,比如上面的demo,將數(shù)組長度設(shè)置為len,那結(jié)果就完全不一樣了,老生代很快就被回收了。
那目標(biāo)能鎖定到數(shù)組擴(kuò)容了
數(shù)組擴(kuò)容
ArrayList里的數(shù)組擴(kuò)容,使用的是System.arrayCopy調(diào)用,這是一個(gè)native方法,在java層面創(chuàng)建一個(gè)新的長度的數(shù)組,然后將老數(shù)組和新數(shù)組都傳進(jìn)去,在native里將老數(shù)組里的元素指針拷貝到新數(shù)組里,其實(shí)做的是淺拷貝,反復(fù)看native這塊實(shí)現(xiàn),也基本解釋不通那個(gè)現(xiàn)象,一度懷疑我對GC的理解了,是不是有哪些細(xì)節(jié)沒有注意到。
經(jīng)過我內(nèi)存dump分析,發(fā)現(xiàn)上面Demo里的List對象確實(shí)被回收了,但是List里的數(shù)組沒有被回收,這個(gè)數(shù)組里的byte數(shù)組都沒有被回收。
原來是這個(gè)鬼
帶著百思不得其解的疑惑和我們組同事討論,看看還有沒有其他可能的沒考慮到疑惑點(diǎn),開始也都覺得疑惑,后來傳勝突然想到會(huì)不會(huì)是存在跨代引用的問題,于是回過來仔細(xì)再想想每個(gè)步驟,好像還真有可能,因?yàn)閭鹘oSystem.arrayCopy的新數(shù)組是在java層面構(gòu)建傳進(jìn)來的,在新生代分配的可能性***,這樣再加上拷貝僅僅是淺拷貝,那么老生代里的byte數(shù)組因?yàn)榇嬖谛律镄聲M的引用,那僅僅做CMS GC就不可能回收這些老生代的對象了,因?yàn)镃MS GC的一個(gè)gc root就是新生代里的對象。
那何解
至此終于抓出了那個(gè)鬼,于是想應(yīng)對策略,既然這樣,只要保證在cms gc回收old之前做一次ygc就能保證新生代里的那個(gè)新數(shù)組被回收而沒有指向老生代那些byte數(shù)組,那么這些數(shù)組就能正常被cms gc回收了,所以加上-XX:+CMSScavengeBeforeRemark即可解此問題。
【本文是專欄作者李嘉鵬的原創(chuàng)文章,轉(zhuǎn)載請通過微信公眾號(你假笨,id:lovestblog)聯(lián)系作者本人獲取授權(quán)】
分享題目:又抓了一個(gè)導(dǎo)致頻繁GC的鬼--數(shù)組動(dòng)態(tài)擴(kuò)容
文章轉(zhuǎn)載:http://www.dlmjj.cn/article/dhdgcdd.html


咨詢
建站咨詢
