最近網(wǎng)上出現(xiàn)一個(gè)美團(tuán)面試題:“一個(gè)線程OOM后彻采,其他線程還能運(yùn)行嗎?”瘫拣。我看網(wǎng)上出現(xiàn)了很多不靠譜的答案亿絮。這道題其實(shí)很有難度,涉及的知識(shí)點(diǎn)有jvm內(nèi)存分配麸拄、作用域派昧、gc等,不是簡(jiǎn)單的是與否的問(wèn)題拢切。
由于題目中給出的OOM蒂萎,java中OOM又分很多類型;比如:堆溢出(“java.lang.OutOfMemoryError: Java heap space”)淮椰、永久帶溢出(“java.lang.OutOfMemoryError:Permgen space”)五慈、不能創(chuàng)建線程(“java.lang.OutOfMemoryError:Unable to create new native thread”)等很多種情況。
本文主要是分析堆溢出對(duì)應(yīng)用帶來(lái)的影響主穗。
直接實(shí)驗(yàn)驗(yàn)證
日志輸入:
從日志可以看出在thead-0發(fā)生OOM之后泻拦,thread-1仍舊能夠繼續(xù)申請(qǐng)內(nèi)存工作。使用jconsole監(jiān)控發(fā)現(xiàn)忽媒,thread-0開始慢慢把heap壓滿争拐,發(fā)生OOM之后神奇的事情發(fā)生了,heap基本上被清空了晦雨,通過(guò)查看jconsole看到的線程信息架曹,發(fā)現(xiàn)沒(méi)有thead-0線程了。這就很明確了闹瞧,因?yàn)閠head-0沒(méi)有捕獲該異常绑雄,跳出了while循環(huán),導(dǎo)致thead-0線程運(yùn)行結(jié)束奥邮,該線程持有的對(duì)象也就能被釋放了万牺。
那如果thread-0發(fā)生了OOM,但是該線程仍舊存活并且持有這些對(duì)象會(huì)怎么樣呢漠烧?
在線程thread-0我們捕獲了該ERROR杏愤,然后讓該線程暫停(不要讓他結(jié)束靡砌,不然又像上面那樣了)輸出日志如下:
在thread-0發(fā)生OOM之后已脓,thread-1在申請(qǐng)內(nèi)存也就發(fā)生了OOM,這個(gè)很容易理解的通殃。
原理分析
我們知道java對(duì)象基本上都是在堆上分配(有特殊情況下度液,不在我們討論的范圍內(nèi))厕宗。小對(duì)象都是直接在Eden區(qū)域中分配。如果此時(shí)內(nèi)存不夠堕担,就會(huì)發(fā)生young gc已慢,如果釋放之后還是內(nèi)存不夠,此時(shí)jvm會(huì)進(jìn)行full gc霹购。如果發(fā)生full gc之后內(nèi)存還是不夠佑惠,此時(shí)就會(huì)拋出“java.lang.OutOfMemoryError: Java heap space”。大對(duì)象jvm會(huì)直接在old 區(qū)域中申請(qǐng)齐疙,但是和小對(duì)象分配的原理類似膜楷。
一般情況下,java對(duì)象內(nèi)存分配跟線程無(wú)關(guān)(TLAB例外)贞奋,能夠申請(qǐng)成功至于當(dāng)前只和當(dāng)前heap空余空間有關(guān)赌厅。
清楚了內(nèi)存分配原理之后,我們就可以以此為基礎(chǔ)來(lái)分析各種情況轿塔。比如:在MyThread0中bytesList放在try中特愿,代碼如下:
MyThread0發(fā)生OOM之后,bytesList其實(shí)就不屬于存活對(duì)象勾缭,gc的時(shí)候就被釋放了揍障。
再比如發(fā)生OOM捕獲該異常之后,因?yàn)槿罩据斎氲膕tring需要占用heap空間漫拭,也可能導(dǎo)致MyThread0再次發(fā)生OOM亚兄,MyThread0線程終結(jié)。
再比如MyThread0中一次性申請(qǐng)的內(nèi)存太大采驻,比如超過(guò)heap大猩笈摺;其他申請(qǐng)小內(nèi)存的線程肯定不會(huì)受到影響礼旅。
總結(jié)
發(fā)生OOM之后會(huì)不會(huì)影響其他線程正常工作需要具體的場(chǎng)景分析膳叨。但是就一般情況下,發(fā)生OOM的線程都會(huì)終結(jié)(除非代碼寫的太爛)痘系,該線程持有的對(duì)象占用的heap都會(huì)被gc了菲嘴,釋放內(nèi)存。
因?yàn)榘l(fā)生OOM之前要進(jìn)行g(shù)c汰翠,就算其他線程能夠正常工作龄坪,也會(huì)因?yàn)轭l繁gc產(chǎn)生較大的影響。
在此我向大家推薦一個(gè)架構(gòu)學(xué)習(xí)交流群复唤。交流學(xué)習(xí)群號(hào):736220120 ?里面會(huì)分享一些資深架構(gòu)師錄制的視頻錄像:有Spring健田,MyBatis,Netty源碼分析佛纫,高并發(fā)妓局、高性能总放、分布式、微服務(wù)架構(gòu)的原理好爬,JVM性能優(yōu)化局雄、分布式架構(gòu)等這些成為架構(gòu)師必備的知識(shí)體系。還能領(lǐng)取免費(fèi)的學(xué)習(xí)資源存炮,目前受益良多炬搭。