JVM學(xué)習(xí)4·內(nèi)存溢出

內(nèi)存溢出,也就是Out Of Memory,應(yīng)該是比較常見的問題吧,這篇我們就好好分析一下內(nèi)存溢出的幾種情況

1.棧溢出 (java.lang.StackOverflowError)

1.1方法自調(diào)用例子

棧溢出就是發(fā)生在棧的內(nèi)存空間溢出的情況,以下這個(gè)例子就很好的可以模擬出這樣的環(huán)境



圖中方法就是不斷的自己調(diào)用自己,這樣導(dǎo)致就是不斷的將方法壓棧,但是無(wú)法出棧,這樣就導(dǎo)致本來(lái)就有單個(gè)虛擬機(jī)棧內(nèi)存限制(默認(rèn)1M)的??臻g終將溢出。

1.2線程過(guò)多

關(guān)于虛擬機(jī)棧整體是沒有內(nèi)存限制的,但是對(duì)于單個(gè)的虛擬機(jī)棧是有限制,默認(rèn)是1M,那么如果線程一直不斷的新增啟動(dòng)就會(huì)導(dǎo)致??臻g終將耗盡,最終導(dǎo)致整個(gè)機(jī)器卡死。

2.堆溢出

2.1 對(duì)象過(guò)多 java.lang.OutOfMemoryError: Java heap space

如圖,我們?cè)趈vm設(shè)置了堆空間的大小為30M,結(jié)果一下子就創(chuàng)建了超過(guò)30M的數(shù)組,當(dāng)然一下就直接溢出了。


2.2 GC占據(jù)98%的資源 GC Overhead Limit Exceeded Error

如圖,我們創(chuàng)建了一個(gè)集合,然后不斷的往里面添加對(duì)象,那么最終會(huì)達(dá)到堆內(nèi)存的限制,在限制之前會(huì)不斷的GC回收垃圾,但是每次都無(wú)法回收很多垃圾,因?yàn)樽疃嗟膶?duì)象仍然被集合引用著,所以說(shuō)有很多的GC,但是就是無(wú)法回收垃圾,最終導(dǎo)致內(nèi)存溢出。

OutOfMemoryError是java.lang.VirtualMachineError的子類,當(dāng)JVM資源利用出現(xiàn)問題時(shí)拋出,更具體地說(shuō),這個(gè)錯(cuò)誤是由于JVM花費(fèi)太長(zhǎng)時(shí)間執(zhí)行GC且只能回收很少的堆內(nèi)存時(shí)拋出的。根據(jù)Oracle官方文檔,默認(rèn)情況下,如果Java進(jìn)程花費(fèi)98%以上的時(shí)間執(zhí)行GC,并且每次只有不到2%的堆被恢復(fù),則JVM拋出此錯(cuò)誤。換句話說(shuō),這意味著我們的應(yīng)用程序幾乎耗盡了所有可用內(nèi)存,垃圾收集器花了太長(zhǎng)時(shí)間試圖清理它,并多次失敗。

在這種情況下,用戶會(huì)體驗(yàn)到應(yīng)用程序響應(yīng)非常緩慢,通常只需要幾毫秒就能完成的某些操作,此時(shí)則需要更長(zhǎng)的時(shí)間來(lái)完成,這是因?yàn)樗械腃PU正在進(jìn)行垃圾收集,因此無(wú)法執(zhí)行其他任務(wù)。

3.方法區(qū)溢出

在之前的JVM內(nèi)存結(jié)構(gòu)中我們知道在方法區(qū)會(huì)存放靜態(tài)常量,靜態(tài)變量,還有類信息等。所以如果想導(dǎo)致方法區(qū)內(nèi)存溢出,我們就可以不斷的添加類來(lái)導(dǎo)致:

首先我們需要添加cglib這個(gè)包:


然后就可以使用該包提供的方法不斷的加載類:

還要設(shè)置一下方法區(qū)的大小限制來(lái)模擬


4.本機(jī)直接內(nèi)存溢出

這塊我們基本不會(huì)用到,他就是操作在jvm之外的內(nèi)存


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容