日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
如果線上遇到了OOM,該如何解決?

OOM 意味著程序存在著漏洞,可能是代碼或者 JVM 參數(shù)配置引起的。這篇文章和讀者聊聊,Java 進(jìn)程觸發(fā)了 OOM 后如何排查?

成都創(chuàng)新互聯(lián)公司是一家專業(yè)提供沈陽企業(yè)網(wǎng)站建設(shè),專注與網(wǎng)站建設(shè)、成都網(wǎng)站制作、H5開發(fā)、小程序制作等業(yè)務(wù)。10年已為沈陽眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站建設(shè)公司優(yōu)惠進(jìn)行中。

常說對(duì)生產(chǎn)環(huán)境保持敬畏之心,快速解決問題也是一種敬畏的表現(xiàn)。

為什么會(huì) OOM

OOM全稱 “Out Of Memory”,表示內(nèi)存耗盡。當(dāng) JVM 因?yàn)闆]有足夠的內(nèi)存來為對(duì)象分配空間,并且垃圾回收器也已經(jīng)沒有空間可回收時(shí),就會(huì)拋出這個(gè)錯(cuò)誤。

為什么會(huì)出現(xiàn) OOM,一般由這些問題引起。

  • 分配過少:JVM 初始化內(nèi)存小,業(yè)務(wù)使用了大量?jī)?nèi)存;或者不同 JVM 區(qū)域分配內(nèi)存不合理
  • 代碼漏洞:某一個(gè)對(duì)象被頻繁申請(qǐng),不用了之后卻沒有被釋放,導(dǎo)致內(nèi)存耗盡
  • 內(nèi)存泄漏:申請(qǐng)使用完的內(nèi)存沒有釋放,導(dǎo)致虛擬機(jī)不能再次使用該內(nèi)存,此時(shí)這段內(nèi)存就泄露了。因?yàn)樯暾?qǐng)者不用了,而又不能被虛擬機(jī)分配給別人用
  • 內(nèi)存溢出:申請(qǐng)的內(nèi)存超出了 JVM 能提供的內(nèi)存大小,此時(shí)稱之為溢出

內(nèi)存泄漏持續(xù)存在,最后一定會(huì)溢出,兩者是因果關(guān)系

常見的 OOM

比較常見的 OOM 類型有以下幾種:

java.lang.OutOfMemoryError: PermGen space

Java7 永久代(方法區(qū))溢出,它用于存儲(chǔ)已被虛擬機(jī)加載的類信息、常量、靜態(tài)變量、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。每當(dāng)一個(gè)類初次加載的時(shí)候,元數(shù)據(jù)都會(huì)存放到永久代

一般出現(xiàn)于大量 Class 對(duì)象或者 JSP 頁面,或者采用 CgLib 動(dòng)態(tài)代理技術(shù)導(dǎo)致

我們可以通過 -XX:PermSize 和 -XX:MaxPermSize 修改方法區(qū)大小

  • Java8 將永久代變更為元空間,報(bào)錯(cuò):java.lang.OutOfMemoryError: Metadata space,元空間內(nèi)存不足默認(rèn)進(jìn)行動(dòng)態(tài)擴(kuò)展

java.lang.StackOverflowError

虛擬機(jī)棧溢出,一般是由于程序中存在 死循環(huán)或者深度遞歸調(diào)用 造成的。如果棧大小設(shè)置過小也會(huì)出現(xiàn)溢出,可以通過 -Xss 設(shè)置棧的大小

虛擬機(jī)拋出棧溢出錯(cuò)誤,可以在日志中定位到錯(cuò)誤的類、方法

java.lang.OutOfMemoryError: Java heap space

Java 堆內(nèi)存溢出,溢出的原因一般由于 JVM 堆內(nèi)存設(shè)置不合理或者內(nèi)存泄漏導(dǎo)致

如果是內(nèi)存泄漏,可以通過工具查看泄漏對(duì)象到 GC Roots 的引用鏈。掌握了泄漏對(duì)象的類型信息以及 GC Roots 引用鏈信息,就可以精準(zhǔn)地定位出泄漏代碼的位置

如果不存在內(nèi)存泄漏,就是內(nèi)存中的對(duì)象確實(shí)都還必須存活著,那就應(yīng)該檢查虛擬機(jī)的堆參數(shù)(-Xmx 與 -Xms),查看是否可以將虛擬機(jī)的內(nèi)存調(diào)大些

小結(jié):方法區(qū)和虛擬機(jī)棧的溢出場(chǎng)景不在本篇過多討論,下面主要講解常見的 Java 堆空間的 OOM 排查思路

查看 JVM 內(nèi)存分布

假設(shè)我們 Java 應(yīng)用 PID 為 15162,輸入命令查看 JVM 內(nèi)存分布 jmap -heap 15162

 
 
 
 
  1. [xxx@xxx ~]# jmap -heap 15162 
  2. Attaching to process ID 15162, please wait... 
  3. Debugger attached successfully. 
  4. Server compiler detected. 
  5. JVM version is 25.161-b12 
  6.  
  7. using thread-local object allocation. 
  8. Mark Sweep Compact GC 
  9.  
  10. Heap Configuration: 
  11.    MinHeapFreeRatio         = 40 # 最小堆使用比例 
  12.    MaxHeapFreeRatio         = 70 # 最大堆可用比例 
  13.    MaxHeapSize              = 482344960 (460.0MB) # 最大堆空間大小 
  14.    NewSize                  = 10485760 (10.0MB) # 新生代分配大小 
  15.    MaxNewSize               = 160759808 (153.3125MB) # 最大新生代可分配大小 
  16.    OldSize                  = 20971520 (20.0MB) # 老年代大小 
  17.    NewRatio                 = 2 # 新生代比例 
  18.    SurvivorRatio            = 8 # 新生代與 Survivor 比例 
  19.    MetaspaceSize            = 21807104 (20.796875MB) # 元空間大小 
  20.    CompressedClassSpaceSize = 1073741824 (1024.0MB) # Compressed Class Space 空間大小限制 
  21.    MaxMetaspaceSize         = 17592186044415 MB # 最大元空間大小 
  22.    G1HeapRegionSize         = 0 (0.0MB) # G1 單個(gè) Region 大小 
  23.  
  24. Heap Usage:  # 堆使用情況 
  25. New Generation (Eden + 1 Survivor Space): # 新生代 
  26.    capacity = 9502720 (9.0625MB) # 新生代總?cè)萘?nbsp;
  27.    used     = 4995320 (4.763908386230469MB) # 新生代已使用 
  28.    free     = 4507400 (4.298591613769531MB) # 新生代剩余容量 
  29.    52.56726495150862% used # 新生代使用占比 
  30. Eden Space:   
  31.    capacity = 8454144 (8.0625MB) # Eden 區(qū)總?cè)萘?nbsp;
  32.    used     = 4029752 (3.8430709838867188MB) # Eden 區(qū)已使用 
  33.    free     = 4424392 (4.219429016113281MB) # Eden 區(qū)剩余容量 
  34.    47.665996699370154% used  # Eden 區(qū)使用占比 
  35. From Space: # 其中一個(gè) Survivor 區(qū)的內(nèi)存分布 
  36.    capacity = 1048576 (1.0MB) 
  37.    used     = 965568 (0.92083740234375MB) 
  38.    free     = 83008 (0.07916259765625MB) 
  39.    92.083740234375% used 
  40. To Space: # 另一個(gè) Survivor 區(qū)的內(nèi)存分布 
  41.    capacity = 1048576 (1.0MB) 
  42.    used     = 0 (0.0MB) 
  43.    free     = 1048576 (1.0MB) 
  44.    0.0% used 
  45. tenured generation: # 老年代 
  46.    capacity = 20971520 (20.0MB) 
  47.    used     = 10611384 (10.119804382324219MB) 
  48.    free     = 10360136 (9.880195617675781MB) 
  49.    50.599021911621094% used 
  50.  
  51. 10730 interned Strings occupying 906232 bytes. 

通過查看 JVM 內(nèi)存分配以及運(yùn)行時(shí)使用情況,可以判斷內(nèi)存分配是否合理

另外,可以在 JVM 運(yùn)行時(shí)查看最耗費(fèi)資源的對(duì)象,jmap -histo:live 15162 | more

JVM 內(nèi)存對(duì)象列表按照對(duì)象所占內(nèi)存大小排序

  • instances:實(shí)例數(shù)
  • bytes:?jiǎn)挝?byte
  • class name:類名

明顯看到 CustomObjTest 對(duì)象實(shí)例以及占用內(nèi)存過多

可惜的是,方案存在局限性,因?yàn)樗荒芘挪閷?duì)象占用內(nèi)存過高問題

其中 "[" 代表數(shù)組,例如 "[C" 代表 Char 數(shù)組,"[B" 代表 Byte 數(shù)組。如果數(shù)組內(nèi)存占用過多,我們不知道哪些對(duì)象持有它,所以就需要 Dump 內(nèi)存進(jìn)行離線分析

jmap -histo:live 執(zhí)行此命令,JVM 會(huì)先觸發(fā) GC,再統(tǒng)計(jì)信息

Dump 文件分析

Dump 文件是 Java 進(jìn)程的內(nèi)存鏡像,其中主要包括 系統(tǒng)信息、虛擬機(jī)屬性、完整的線程 Dump、所有類和對(duì)象的狀態(tài) 等信息

當(dāng)程序發(fā)生內(nèi)存溢出或 GC 異常情況時(shí),懷疑 JVM 發(fā)生了 內(nèi)存泄漏,這時(shí)我們就可以導(dǎo)出 Dump 文件分析

JVM 啟動(dòng)參數(shù)配置添加以下參數(shù)

  • -XX:+HeapDumpOnOutOfMemoryError
  • -XX:HeapDumpPath=./(參數(shù)為 Dump 文件生成路徑)

當(dāng) JVM 發(fā)生 OOM 異常自動(dòng)導(dǎo)出 Dump 文件,文件名稱默認(rèn)格式:java_pid{pid}.hprof

上面配置是在應(yīng)用拋出 OOM 后自動(dòng)導(dǎo)出 Dump,或者可以在 JVM 運(yùn)行時(shí)導(dǎo)出 Dump 文件

 
 
 
 
  1. jmap -dump:file=[文件路徑] [pid] 
  2.  
  3. # 示例 
  4. jmap -dump:file=./jvmdump.hprof 15162 

在本地寫一個(gè)測(cè)試代碼,驗(yàn)證下 OOM 以及分析 Dump 文件

 
 
 
 
  1. 設(shè)置 VM 參數(shù):-Xms3m -Xmx3m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./ 
  2.  
  3. public static void main(String[] args) { 
  4.     List oomList = Lists.newArrayList(); 
  5.    // 無限循環(huán)創(chuàng)建對(duì)象 
  6.     while (true) { 
  7.         oomList.add(new Object()); 
  8.     } 
  9. 通過報(bào)錯(cuò)信息得知,java heap space 表示 OOM 發(fā)生在堆區(qū),并生成了 hprof 二進(jìn)制文件在當(dāng)前文件夾下

    JvisualVM 分析

    Dump 分析工具有很多,相對(duì)而言 JvisualVM、JProfiler、Eclipse Mat,使用人群更多一些。下面以 JvisualVM 舉例分析 Dump 文件

    列舉兩個(gè)常用的功能,第一個(gè)是能看到觸發(fā) OOM 的線程堆棧,清晰得知程序溢出的原因

    第二個(gè)就是可以查看 JVM 內(nèi)存里保留大小最大的對(duì)象,可以自由選擇排查個(gè)數(shù)

    點(diǎn)擊對(duì)象還可以跳轉(zhuǎn)具體的對(duì)象引用詳情頁面

    文中 Dump 文件較為簡(jiǎn)單,而正式環(huán)境出錯(cuò)的原因五花八門,所以不對(duì)該 Dump 文件做深度解析

    注意:JvisualVM 如果分析大 Dump 文件,可能會(huì)因?yàn)閮?nèi)存不足打不開,需要調(diào)整默認(rèn)的內(nèi)存

    總結(jié)回顧

    線上如遇到 JVM 內(nèi)存溢出,可以分以下幾步排查

    1. jmap -heap 查看是否內(nèi)存分配過小
    2. jmap -histo 查看是否有明顯的對(duì)象分配過多且沒有釋放情況
    3. jmap -dump 導(dǎo)出 JVM 當(dāng)前內(nèi)存快照,使用 JDK 自帶或 MAT 等工具分析快照

    如果上面還不能定位問題,那么需要排查應(yīng)用是否在不斷創(chuàng)建資源,比如網(wǎng)絡(luò)連接或者線程,都可能會(huì)導(dǎo)致系統(tǒng)資源耗盡

    本文轉(zhuǎn)載自微信公眾號(hào)「龍臺(tái)的技術(shù)筆記」


    本文名稱:如果線上遇到了OOM,該如何解決?
    網(wǎng)頁網(wǎng)址:http://www.dlmjj.cn/article/djpjsos.html