最容易引發(fā)內(nèi)存溢出的,就是系統(tǒng)創(chuàng)建出來的對象!
1 對象在Eden區(qū)分配
系統(tǒng)運(yùn)行時(shí),一直不停創(chuàng)建對象,然后大量對象會(huì)填滿Eden。?Eden滿,就會(huì)觸發(fā)一次YGC,然后存活對象進(jìn)入S區(qū):
2 高并發(fā)場景導(dǎo)致YGC后,存活對象太多
高并發(fā)場景,導(dǎo)致YGC后很多請求還沒處理完,存活對象太多,可能就在S區(qū)放不下,只能進(jìn)入Old,Old很快就會(huì)滿了:
一旦Old放滿,就會(huì)觸發(fā)Full GC。
假設(shè)YGC后,有一批存活對象,S放不下,就等著要進(jìn)入Old,然后Old也滿,就得等Old進(jìn)行CMS GC,必須回收掉一批對象,才能讓年輕代里存活的一批對象進(jìn)去。
但Old GC后,依然存活下很多對象,這時(shí)若年輕代還有一批對象等著進(jìn)Old,可Old空間還是不足,咋辦? 只能內(nèi)存溢出!?
所以這時(shí),Old都已滿,你還要往里面放東西,而且觸發(fā)Full GC回收了Old還是沒足夠內(nèi)存空間,你卻還要放, 那只能給你個(gè)內(nèi)存溢出!JVM崩潰。
3 何時(shí)發(fā)生堆內(nèi)存溢出?
有限的內(nèi)存中放了過多的對象,而且大多數(shù)都是存活的,此時(shí)即使GC過后還是大部分都存活,所以要繼續(xù)放入更多對象已經(jīng)不可能了,此時(shí)只能引發(fā)內(nèi)存溢出。
發(fā)生內(nèi)存溢出的主要場景:
- 系統(tǒng)承載高并發(fā)請求,因請求量過大,導(dǎo)致大量對象都存活,所以要繼續(xù)放入新對象,實(shí)在不行了,就會(huì)引發(fā)OOM
- 系統(tǒng)有內(nèi)存泄露,即莫名其妙弄了很多對象,結(jié)果對象都存活,沒有及時(shí)取消對他們的引用,導(dǎo)致觸發(fā)GC還是無法回收,也只能引發(fā)內(nèi)存溢出
綜上,一般引發(fā)OOM,要不然是系統(tǒng)負(fù)載過高,要不然就是有內(nèi)存泄露。
4 總結(jié)
堆內(nèi)存OOM的根本原因,即對象太多,且都是存活的,即使GC過后還是沒有空間了,此時(shí)放不下新的對象,JVM只能選擇崩潰!