<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試官:哪些場(chǎng)景會(huì)產(chǎn)生OOM?怎么解決?

          共 5297字,需瀏覽 11分鐘

           ·

          2020-09-23 23:43

          這個(gè)面試題是一個(gè)朋友在面試的時(shí)候碰到的,什么時(shí)候會(huì)拋出OutOfMemery異常呢?初看好像挺簡(jiǎn)單的,其實(shí)深究起來(lái)考察的是對(duì)整個(gè)JVM的了解,而且這個(gè)問(wèn)題從網(wǎng)上可以翻到一些亂七八糟的答案,其實(shí)在總結(jié)下來(lái)基本上4個(gè)場(chǎng)景可以概括下來(lái)。

          堆內(nèi)存溢出

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

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

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

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

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

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

          火焰圖

          方法區(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  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,可以看見(jiàn)堆內(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ì)看見(jiàn)PermGen space的報(bào)錯(cuò)。

          直接內(nèi)存溢出

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

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

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

          棧內(nèi)存溢出

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

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

          1. 如果線程請(qǐng)求的棧深度大于虛擬機(jī)所允許的深度,將拋出StackOverflowError異常
          2. 如果虛擬機(jī)棧可以動(dòng)態(tài)擴(kuò)展,并且擴(kuò)展時(shí)無(wú)法申請(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),單線程下無(wú)論怎么設(shè)置參數(shù)都是StackOverflow異常。

          嘗試把代碼修改為多線程,調(diào)整-Xss2m,因?yàn)闉槊總€(gè)線程分配的內(nèi)存越大,棧空間可容納的線程數(shù)量越少,越容易產(chǎn)生內(nèi)存溢出。反之,如果內(nèi)存不夠的情況,可以調(diào)小該參數(shù)來(lái)達(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();
              }
          }

          Python中文社區(qū)作為一個(gè)去中心化的全球技術(shù)社區(qū),以成為全球20萬(wàn)Python中文開(kāi)發(fā)者的精神部落為愿景,目前覆蓋各大主流媒體和協(xié)作平臺(tái),與阿里、騰訊、百度、微軟、亞馬遜、開(kāi)源中國(guó)、CSDN等業(yè)界知名公司和技術(shù)社區(qū)建立了廣泛的聯(lián)系,擁有來(lái)自十多個(gè)國(guó)家和地區(qū)數(shù)萬(wàn)名登記會(huì)員,會(huì)員來(lái)自以工信部、清華大學(xué)、北京大學(xué)、北京郵電大學(xué)、中國(guó)人民銀行、中科院、中金、華為、BAT、谷歌、微軟等為代表的政府機(jī)關(guān)、科研單位、金融機(jī)構(gòu)以及海內(nèi)外知名公司,全平臺(tái)近20萬(wàn)開(kāi)發(fā)者關(guān)注。


          長(zhǎng)按掃碼添加“Python小助手”



          ▼點(diǎn)擊成為社區(qū)會(huì)員   喜歡就點(diǎn)個(gè)在看吧

          瀏覽 63
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  大香蕉福利资源视频 | 国产老骚逼 | 国产日本精品视频 | 天干天干天夜夜 | 亚洲1区无码 |