自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

如果線上遇到了OOM,該如何解決?

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

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

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

為什么會 OOM

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

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

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

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

常見的 OOM

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

java.lang.OutOfMemoryError: PermGen space

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

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

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

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

java.lang.StackOverflowError

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

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

java.lang.OutOfMemoryError: Java heap space

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

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

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

小結(jié):方法區(qū)和虛擬機棧的溢出場景不在本篇過多討論,下面主要講解常見的 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 單個 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: # 其中一個 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: # 另一個 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)存分配以及運行時使用情況,可以判斷內(nèi)存分配是否合理

另外,可以在 JVM 運行時查看最耗費資源的對象,jmap -histo:live 15162 | more

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

  • instances:實例數(shù)
  • bytes:單位 byte
  • class name:類名

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

可惜的是,方案存在局限性,因為它只能排查對象占用內(nèi)存過高問題

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

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

Dump 文件分析

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

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

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

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

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

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

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

在本地寫一個測試代碼,驗證下 OOM 以及分析 Dump 文件

  1. 設(shè)置 VM 參數(shù):-Xms3m -Xmx3m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./ 
  2.  
  3. public static void main(String[] args) { 
  4.     List<Object> oomList = Lists.newArrayList(); 
  5.    // 無限循環(huán)創(chuàng)建對象 
  6.     while (true) { 
  7.         oomList.add(new Object()); 
  8.     } 

通過報錯信息得知,java heap space 表示 OOM 發(fā)生在堆區(qū),并生成了 hprof 二進制文件在當前文件夾下

JvisualVM 分析

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

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

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

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

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

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

總結(jié)回顧

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

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

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

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

 

責任編輯:姜華 來源: 龍臺的技術(shù)筆記
相關(guān)推薦

2024-01-10 09:44:11

MySQL死鎖

2024-10-10 15:32:51

2021-06-28 21:04:09

顯示器花屏電腦

2024-09-25 14:25:47

API接口

2018-11-14 12:18:35

設(shè)計畫面太亂視覺元素

2019-02-25 11:16:29

Windows 10錯誤distributed

2024-01-16 08:26:25

Vue項目服務(wù)器

2021-03-04 17:21:49

內(nèi)存檢測泄漏

2024-06-21 09:37:57

2015-04-01 10:26:32

開發(fā)中文亂碼問題

2021-12-08 12:05:21

MySQ磁盤數(shù)據(jù)庫

2022-03-16 07:58:02

OOMdubbo內(nèi)存

2022-10-10 08:05:34

線程池OOM問題

2023-03-10 08:24:27

OOMdump線程

2013-11-05 09:30:02

社交媒體法規(guī)合規(guī)

2015-05-15 17:29:13

.Netxp系統(tǒng)如何解決

2011-08-18 15:56:03

深信服廣域網(wǎng)優(yōu)化

2016-12-13 11:34:10

2014-01-22 09:25:44

2009-12-10 14:19:41

配置靜態(tài)路由
點贊
收藏

51CTO技術(shù)棧公眾號