為什么會(huì)出現(xiàn)OOM?如何解決OOM

一 堆內(nèi)存溢出

堆內(nèi)存溢出太常見,大部分人都應(yīng)該能想得到這一點(diǎn)漾狼,堆內(nèi)存用來存儲(chǔ)對(duì)象實(shí)例重慢,我們只要不停的創(chuàng)建對(duì)象,并且保證GC Roots和對(duì)象之間有可達(dá)路徑避免垃圾回收逊躁,那么在對(duì)象數(shù)量超過最大堆的大小限制后很快就能出現(xiàn)這個(gè)異常

寫一段代碼測(cè)試一下似踱,設(shè)置堆內(nèi)存大小2M

public class HeapOOM {
    public static void main(String[] args) {
        List<HeapOOM> list = new ArrayList<>();
        while (true) {
            list.add(new HeapOOM());
        }
    }
}

運(yùn)行代碼,很快能看見OOM異常出現(xiàn)志衣,這里的提示是Java heap space堆內(nèi)存溢出

一般的排查方式可以通過設(shè)置-XX: +HeapDumpOnOutOfMemoryError在發(fā)生異常時(shí)dump出當(dāng)前的內(nèi)存轉(zhuǎn)儲(chǔ)快照來分析屯援,分析可以使用Eclipse Memory Analyzer(MAT)來分析,獨(dú)立文件可以在官網(wǎng)下載

另外如果使用的是IDEA的話念脯,可以使用商業(yè)版JProfiler或者開源版本的JVM-Profiler狞洋,此外IDEA2018版本之后內(nèi)置了分析工具,包括Flame Graph(火焰圖)和Call Tree(調(diào)用樹)功能

二 方法區(qū)(運(yùn)行時(shí)常量池)和元空間溢出

方法區(qū)和堆一樣绿店,是線程共享的區(qū)域吉懊,包含Class文件信息、運(yùn)行時(shí)常量池假勿、常量池借嗽,運(yùn)行時(shí)常量池和常量池的主要區(qū)別是具備動(dòng)態(tài)性,也就是不一定非要是在Class文件中的常量池中的內(nèi)容才能進(jìn)入運(yùn)行時(shí)常量池转培,運(yùn)行期間也可以可以將新的常量放入池中恶导,比如String的intern()方法

我們寫一段代碼驗(yàn)證一下String.intern(),同時(shí)我們?cè)O(shè)置-XX:MetaspaceSize=50m -XX:MaxMetaspaceSize=50m 元空間大小浸须。由于我使用的是1.8版本的JDK惨寿,而1.8版本之前方法區(qū)存在于永久代(PermGen),1.8之后取消了永久代的概念删窒,轉(zhuǎn)為元空間(Metaspace)裂垦,如果是之前版本可以設(shè)置PermSize MaxPermSize永久代的大小

 private static String str = "test";
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        while (true){
            String str2 = str + str;
            str = str2;
            list.add(str.intern());
        }
}

運(yùn)行代碼,會(huì)發(fā)現(xiàn)代碼報(bào)錯(cuò)



再次修改配置肌索,去除元空間限制蕉拢,修改堆內(nèi)存大小-Xms20m -Xmx20m,可以看見堆內(nèi)存報(bào)錯(cuò)诚亚。


這是為什么呢晕换?

intern()本身是一個(gè)native方法,它的作用是:如果字符串常量池中已經(jīng)包含一個(gè)等 于此String對(duì)象的字符串亡电,則返回代表池中這個(gè)字符串的String對(duì)象;否則届巩,將此String對(duì)象包含的字符串添加到常量池中,并且返回String對(duì)象的引用

而在1.7版本之后份乒,字符串常量池已經(jīng)轉(zhuǎn)移到堆區(qū)恕汇,所以會(huì)報(bào)出堆內(nèi)存溢出的錯(cuò)誤腕唧,如果1.7之前版本的話會(huì)看見PermGen space的報(bào)錯(cuò)

三 直接內(nèi)存溢出

直接內(nèi)存并不是虛擬機(jī)運(yùn)行時(shí)數(shù)據(jù)區(qū)域的一部分,并且不受堆內(nèi)存的限制瘾英,但是受到機(jī)器內(nèi)存大小的限制枣接。常見的比如在NIO中可以使用native函數(shù)直接分配堆外內(nèi)存就容易導(dǎo)致OOM的問題

直接內(nèi)存大小可以通過-XX:MaxDirectMemorySize指定,如果不指定缺谴,則默認(rèn)與Java 堆最大值-Xmx一樣

由直接內(nèi)存導(dǎo)致的內(nèi)存溢出但惶,一個(gè)明顯的特征是在Dump文件中不會(huì)看見明顯的異常,如果發(fā)現(xiàn)OOM之后Dump文件很小湿蛔,而程序中又直接或間接使用了NIO膀曾,那就可以考慮檢查一下是不是這方面的原因

四 棧內(nèi)存溢出

棧是線程私有,它的生命周期和線程相同阳啥。每個(gè)方法在執(zhí)行的同時(shí)都會(huì)創(chuàng)建一個(gè)棧幀用于存儲(chǔ)局部變量表添谊、操作數(shù)棧、動(dòng)態(tài)鏈接察迟、方法出口等信息斩狱,方法調(diào)用的過程就是棧幀入棧和出棧的過程

在java虛擬機(jī)規(guī)范中,對(duì)虛擬機(jī)棧定義了兩種異常:

1.如果線程請(qǐng)求的棧深度大于虛擬機(jī)所允許的深度扎瓶,將拋出StackOverflowError異常

2.如果虛擬機(jī)椝唬可以動(dòng)態(tài)擴(kuò)展,并且擴(kuò)展時(shí)無法申請(qǐng)到足夠的內(nèi)存概荷,拋出OutOfMemoryError異常

先寫一段代碼測(cè)試一下秕岛,設(shè)置-Xss160k,-Xss代表每個(gè)線程的棧內(nèi)存大小

public class StackOOM {
    private int length = 1;

    public void stackTest() {
        System.out.println("stack lenght=" + length);
        length++;
        stackTest();
    }

    public static void main(String[] args) {
        StackOOM test = new StackOOM();
        test.stackTest();
    }
}

測(cè)試發(fā)現(xiàn)误证,單線程下無論怎么設(shè)置參數(shù)都是StackOverflow異常


嘗試把代碼修改為多線程瓣蛀,調(diào)整-Xss2m,因?yàn)闉槊總€(gè)線程分配的內(nèi)存越大雷厂,棧空間可容納的線程數(shù)量越少叠殷,越容易產(chǎn)生內(nèi)存溢出改鲫。反之,如果內(nèi)存不夠的情況林束,可以調(diào)小該參數(shù)來達(dá)到支撐更多線程的目的

public class StackOOM {
    private void dontStop() {
        while (true) {
        }
    }

    public void stackLeakByThread() {
        while (true) {
            new Thread(() -> dontStop()).start();
        }
    }

    public static void main(String[] args) throws Throwable {
        StackOOM stackOOM = new StackOOM();
        stackOOM.stackLeakByThread();
    }
}

文章來源于網(wǎng)絡(luò):源文地址:https://juejin.cn/post/6902278105222610951

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末像棘,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子壶冒,更是在濱河造成了極大的恐慌缕题,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胖腾,死亡現(xiàn)場(chǎng)離奇詭異烟零,居然都是意外死亡瘪松,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門锨阿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宵睦,“玉大人,你說我怎么就攤上這事墅诡】呛浚” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵末早,是天一觀的道長(zhǎng)烟馅。 經(jīng)常有香客問我,道長(zhǎng)然磷,這世上最難降的妖魔是什么郑趁? 我笑而不...
    開封第一講書人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮样屠,結(jié)果婚禮上穿撮,老公的妹妹穿的比我還像新娘。我一直安慰自己痪欲,他們只是感情好悦穿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著业踢,像睡著了一般栗柒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上知举,一...
    開封第一講書人閱讀 51,679評(píng)論 1 305
  • 那天瞬沦,我揣著相機(jī)與錄音,去河邊找鬼雇锡。 笑死逛钻,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的锰提。 我是一名探鬼主播曙痘,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼立肘!你這毒婦竟也來了边坤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤谅年,失蹤者是張志新(化名)和其女友劉穎茧痒,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體融蹂,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡旺订,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年弄企,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片耸峭。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡桩蓉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出劳闹,到底是詐尸還是另有隱情院究,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布本涕,位于F島的核電站业汰,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏菩颖。R本人自食惡果不足惜样漆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望晦闰。 院中可真熱鬧放祟,春花似錦、人聲如沸呻右。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)声滥。三九已至眉撵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間落塑,已是汗流浹背纽疟。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留憾赁,地道東北人污朽。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像龙考,于是被迫代替她去往敵國(guó)和親膘壶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 這個(gè)面試題是一個(gè)朋友在面試的時(shí)候碰到的,什么時(shí)候會(huì)拋出OutOfMemery異常呢官紫?初看好像挺簡(jiǎn)單的肛宋,其實(shí)深究起來...
    艾小仙人閱讀 381評(píng)論 0 0
  • jvm內(nèi)存區(qū)域 程序計(jì)數(shù)器一塊很小的內(nèi)存空間州藕,作用是當(dāng)前線程所執(zhí)行的字節(jié)碼的行號(hào)指示器。 java棧與程序計(jì)數(shù)器一...
    億萬年星空閱讀 467評(píng)論 0 0
  • 一. 可通過命令定期抓取heap dump或者啟動(dòng)參數(shù)OOM時(shí)自動(dòng)抓取heap dump文件酝陈。 二. 通過對(duì)比多個(gè)...
    魚仔_1625閱讀 908評(píng)論 0 0
  • 久違的晴天床玻,家長(zhǎng)會(huì)。 家長(zhǎng)大會(huì)開好到教室時(shí)沉帮,離放學(xué)已經(jīng)沒多少時(shí)間了锈死。班主任說已經(jīng)安排了三個(gè)家長(zhǎng)分享經(jīng)驗(yàn)。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,523評(píng)論 16 22
  • 今天感恩節(jié)哎穆壕,感謝一直在我身邊的親朋好友待牵。感恩相遇!感恩不離不棄喇勋。 中午開了第一次的黨會(huì)缨该,身份的轉(zhuǎn)變要...
    迷月閃星情閱讀 10,567評(píng)論 0 11