日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

javaheapspace解决方案_高手总结的9种 OOM 常见原因及解决方案

發(fā)布時(shí)間:2023/12/18 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 javaheapspace解决方案_高手总结的9种 OOM 常见原因及解决方案 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

當(dāng) JVM 內(nèi)存嚴(yán)重不足時(shí),就會(huì)拋出 java.lang.OutOfMemoryError 錯(cuò)誤。本文總結(jié)了常見(jiàn)的 OOM 原因及其解決方法,如下圖所示。如有遺漏或錯(cuò)誤,歡迎補(bǔ)充指正。

1、Java heap space

當(dāng)堆內(nèi)存(Heap Space)沒(méi)有足夠空間存放新創(chuàng)建的對(duì)象時(shí),就會(huì)拋出 java.lang.OutOfMemoryError:Javaheap space 錯(cuò)誤(根據(jù)實(shí)際生產(chǎn)經(jīng)驗(yàn),可以對(duì)程序日志中的 OutOfMemoryError 配置關(guān)鍵字告警,一經(jīng)發(fā)現(xiàn),立即處理)。

原因分析

Javaheap space 錯(cuò)誤產(chǎn)生的常見(jiàn)原因可以分為以下幾類:

1、請(qǐng)求創(chuàng)建一個(gè)超大對(duì)象,通常是一個(gè)大數(shù)組。

2、超出預(yù)期的訪問(wèn)量/數(shù)據(jù)量,通常是上游系統(tǒng)請(qǐng)求流量飆升,常見(jiàn)于各類促銷/秒殺活動(dòng),可以結(jié)合業(yè)務(wù)流量指標(biāo)排查是否有尖狀峰值。

3、過(guò)度使用終結(jié)器(Finalizer),該對(duì)象沒(méi)有立即被 GC。

4、內(nèi)存泄漏(Memory Leak),大量對(duì)象引用沒(méi)有釋放,JVM 無(wú)法對(duì)其自動(dòng)回收,常見(jiàn)于使用了 File 等資源沒(méi)有回收。

解決方案

針對(duì)大部分情況,通常只需要通過(guò) -Xmx 參數(shù)調(diào)高 JVM 堆內(nèi)存空間即可。如果仍然沒(méi)有解決,可以參考以下情況做進(jìn)一步處理:

1、如果是超大對(duì)象,可以檢查其合理性,比如是否一次性查詢了數(shù)據(jù)庫(kù)全部結(jié)果,而沒(méi)有做結(jié)果數(shù)限制。

2、如果是業(yè)務(wù)峰值壓力,可以考慮添加機(jī)器資源,或者做限流降級(jí)。

3、如果是內(nèi)存泄漏,需要找到持有的對(duì)象,修改代碼設(shè)計(jì),比如關(guān)閉沒(méi)有釋放的連接。

2、GC overhead limit exceeded

當(dāng) Java 進(jìn)程花費(fèi) 98% 以上的時(shí)間執(zhí)行 GC,但只恢復(fù)了不到 2% 的內(nèi)存,且該動(dòng)作連續(xù)重復(fù)了 5 次,就會(huì)拋出 java.lang.OutOfMemoryError:GC overhead limit exceeded 錯(cuò)誤。簡(jiǎn)單地說(shuō),就是應(yīng)用程序已經(jīng)基本耗盡了所有可用內(nèi)存, GC 也無(wú)法回收。

此類問(wèn)題的原因與解決方案跟 Javaheap space 非常類似,可以參考上文。

3、Permgen space

該錯(cuò)誤表示永久代(Permanent Generation)已用滿,通常是因?yàn)榧虞d的 class 數(shù)目太多或體積太大。

原因分析

永久代存儲(chǔ)對(duì)象主要包括以下幾類:

1、加載/緩存到內(nèi)存中的 class 定義,包括類的名稱,字段,方法和字節(jié)碼;

2、常量池;

3、對(duì)象數(shù)組/類型數(shù)組所關(guān)聯(lián)的 class;

4、JIT 編譯器優(yōu)化后的 class 信息。

PermGen 的使用量與加載到內(nèi)存的 class 的數(shù)量/大小正相關(guān)。

解決方案

根據(jù) Permgen space 報(bào)錯(cuò)的時(shí)機(jī),可以采用不同的解決方案,如下所示:

1、程序啟動(dòng)報(bào)錯(cuò),修改 -XX:MaxPermSize 啟動(dòng)參數(shù),調(diào)大永久代空間。

2、應(yīng)用重新部署時(shí)報(bào)錯(cuò),很可能是沒(méi)有應(yīng)用沒(méi)有重啟,導(dǎo)致加載了多份 class 信息,只需重啟 JVM 即可解決。

3、運(yùn)行時(shí)報(bào)錯(cuò),應(yīng)用程序可能會(huì)動(dòng)態(tài)創(chuàng)建大量 class,而這些 class 的生命周期很短暫,但是 JVM 默認(rèn)不會(huì)卸載 class,可以設(shè)置 -XX:+CMSClassUnloadingEnabled 和 -XX:+UseConcMarkSweepGC這兩個(gè)參數(shù)允許 JVM 卸載 class。

如果上述方法無(wú)法解決,可以通過(guò) jmap 命令 dump 內(nèi)存對(duì)象 jmap-dump:format=b,file=dump.hprof<process-id> ,然后利用 Eclipse MAT https://www.eclipse.org/mat 功能逐一分析開(kāi)銷最大的 classloader 和重復(fù) class。

4、Metaspace

JDK 1.8 使用 Metaspace 替換了永久代(Permanent Generation),該錯(cuò)誤表示 Metaspace 已被用滿,通常是因?yàn)榧虞d的 class 數(shù)目太多或體積太大。

此類問(wèn)題的原因與解決方法跟 Permgenspace 非常類似,可以參考上文。需要特別注意的是調(diào)整 Metaspace 空間大小的啟動(dòng)參數(shù)為 -XX:MaxMetaspaceSize。

5、Unable to create new native thread

每個(gè) Java 線程都需要占用一定的內(nèi)存空間,當(dāng) JVM 向底層操作系統(tǒng)請(qǐng)求創(chuàng)建一個(gè)新的 native 線程時(shí),如果沒(méi)有足夠的資源分配就會(huì)報(bào)此類錯(cuò)誤。

原因分析

JVM 向 OS 請(qǐng)求創(chuàng)建 native 線程失敗,就會(huì)拋出 Unableto createnewnativethread,常見(jiàn)的原因包括以下幾類:

1、線程數(shù)超過(guò)操作系統(tǒng)最大線程數(shù) ulimit 限制;

2、線程數(shù)超過(guò) kernel.pid_max(只能重啟);

3、native 內(nèi)存不足;

該問(wèn)題發(fā)生的常見(jiàn)過(guò)程主要包括以下幾步:

1、JVM 內(nèi)部的應(yīng)用程序請(qǐng)求創(chuàng)建一個(gè)新的 Java 線程;

2、JVM native 方法代理了該次請(qǐng)求,并向操作系統(tǒng)請(qǐng)求創(chuàng)建一個(gè) native 線程;

3、操作系統(tǒng)嘗試創(chuàng)建一個(gè)新的 native 線程,并為其分配內(nèi)存;

4、如果操作系統(tǒng)的虛擬內(nèi)存已耗盡,或是受到 32 位進(jìn)程的地址空間限制,操作系統(tǒng)就會(huì)拒絕本次 native 內(nèi)存分配;

5、JVM 將拋出 java.lang.OutOfMemoryError:Unableto createnewnativethread 錯(cuò)誤。

解決方案

1、升級(jí)配置,為機(jī)器提供更多的內(nèi)存;

2、降低 Java Heap Space 大小;

3、修復(fù)應(yīng)用程序的線程泄漏問(wèn)題;

4、限制線程池大小;

5、使用 -Xss 參數(shù)減少線程棧的大小;

6、調(diào)高 OS 層面的線程最大數(shù):執(zhí)行 ulimia-a 查看最大線程數(shù)限制,使用 ulimit-u xxx 調(diào)整最大線程數(shù)限制。

ulimit -a .... 省略部分內(nèi)容 ..... max user processes (-u) 16384

6、Out of swap space?

該錯(cuò)誤表示所有可用的虛擬內(nèi)存已被耗盡。虛擬內(nèi)存(Virtual Memory)由物理內(nèi)存(Physical Memory)和交換空間(Swap Space)兩部分組成。當(dāng)運(yùn)行時(shí)程序請(qǐng)求的虛擬內(nèi)存溢出時(shí)就會(huì)報(bào) Outof swap space? 錯(cuò)誤。

原因分析

該錯(cuò)誤出現(xiàn)的常見(jiàn)原因包括以下幾類:

1、地址空間不足;

2、物理內(nèi)存已耗光;

3、應(yīng)用程序的本地內(nèi)存泄漏(native leak),例如不斷申請(qǐng)本地內(nèi)存,卻不釋放。

4、執(zhí)行 jmap-histo:live<pid> 命令,強(qiáng)制執(zhí)行 Full GC;如果幾次執(zhí)行后內(nèi)存明顯下降,則基本確認(rèn)為 Direct ByteBuffer 問(wèn)題。

解決方案

根據(jù)錯(cuò)誤原因可以采取如下解決方案:

1、升級(jí)地址空間為 64 bit;

2、使用 Arthas 檢查是否為 Inflater/Deflater 解壓縮問(wèn)題,如果是,則顯式調(diào)用 end 方法。

3、Direct ByteBuffer 問(wèn)題可以通過(guò)啟動(dòng)參數(shù) -XX:MaxDirectMemorySize 調(diào)低閾值。

4、升級(jí)服務(wù)器配置/隔離部署,避免爭(zhēng)用。

7、 Kill process or sacrifice child

有一種內(nèi)核作業(yè)(Kernel Job)名為 Out of Memory Killer,它會(huì)在可用內(nèi)存極低的情況下“殺死”(kill)某些進(jìn)程。OOM Killer 會(huì)對(duì)所有進(jìn)程進(jìn)行打分,然后將評(píng)分較低的進(jìn)程“殺死”,具體的評(píng)分規(guī)則可以參考 Surviving the Linux OOM Killer。

不同于其他的 OOM 錯(cuò)誤, Killprocessorsacrifice child 錯(cuò)誤不是由 JVM 層面觸發(fā)的,而是由操作系統(tǒng)層面觸發(fā)的。

原因分析

默認(rèn)情況下,Linux 內(nèi)核允許進(jìn)程申請(qǐng)的內(nèi)存總量大于系統(tǒng)可用內(nèi)存,通過(guò)這種“錯(cuò)峰復(fù)用”的方式可以更有效的利用系統(tǒng)資源。

然而,這種方式也會(huì)無(wú)可避免地帶來(lái)一定的“超賣”風(fēng)險(xiǎn)。例如某些進(jìn)程持續(xù)占用系統(tǒng)內(nèi)存,然后導(dǎo)致其他進(jìn)程沒(méi)有可用內(nèi)存。此時(shí),系統(tǒng)將自動(dòng)激活 OOM Killer,尋找評(píng)分低的進(jìn)程,并將其“殺死”,釋放內(nèi)存資源。

解決方案

1、升級(jí)服務(wù)器配置/隔離部署,避免爭(zhēng)用。

2、OOM Killer 調(diào)優(yōu)。

8、Requested array size exceeds VM limit

JVM 限制了數(shù)組的最大長(zhǎng)度,該錯(cuò)誤表示程序請(qǐng)求創(chuàng)建的數(shù)組超過(guò)最大長(zhǎng)度限制。

JVM 在為數(shù)組分配內(nèi)存前,會(huì)檢查要分配的數(shù)據(jù)結(jié)構(gòu)在系統(tǒng)中是否可尋址,通常為 Integer.MAX_VALUE-2。

此類問(wèn)題比較罕見(jiàn),通常需要檢查代碼,確認(rèn)業(yè)務(wù)是否需要?jiǎng)?chuàng)建如此大的數(shù)組,是否可以拆分為多個(gè)塊,分批執(zhí)行。

9、Direct buffer memory

Java 允許應(yīng)用程序通過(guò) Direct ByteBuffer 直接訪問(wèn)堆外內(nèi)存,許多高性能程序通過(guò) Direct ByteBuffer 結(jié)合內(nèi)存映射文件(Memory Mapped File)實(shí)現(xiàn)高速 IO。

原因分析

Direct ByteBuffer 的默認(rèn)大小為 64 MB,一旦使用超出限制,就會(huì)拋出 Directbuffer memory 錯(cuò)誤。

解決方案

1、Java 只能通過(guò) ByteBuffer.allocateDirect 方法使用 Direct ByteBuffer,因此,可以通過(guò) Arthas 等在線診斷工具攔截該方法進(jìn)行排查。

2、檢查是否直接或間接使用了 NIO,如 netty,jetty 等。

3、通過(guò)啟動(dòng)參數(shù) -XX:MaxDirectMemorySize 調(diào)整 Direct ByteBuffer 的上限值。

4、檢查 JVM 參數(shù)是否有 -XX:+DisableExplicitGC 選項(xiàng),如果有就去掉,因?yàn)樵搮?shù)會(huì)使 System.gc() 失效。

5、檢查堆外內(nèi)存使用代碼,確認(rèn)是否存在內(nèi)存泄漏;或者通過(guò)反射調(diào)用 sun.misc.Cleaner 的 clean() 方法來(lái)主動(dòng)釋放被 Direct ByteBuffer 持有的內(nèi)存空間。

6、內(nèi)存容量確實(shí)不足,升級(jí)配置。

推薦工具&產(chǎn)品

JVM 內(nèi)存分析工具 mat

1、Eclipse Memory Analyzer

https://www.eclipse.org/mat

阿里云 APM 產(chǎn)品,支持 OOM 異常關(guān)鍵字告警

2、ARMS

https://help.aliyun.com/document_detail/42966.html?spm=a2c4g.11174283.6.685.d69b668cuztvff

阿里 Java 在線診斷工具 Arthas(阿爾薩斯)

3、alibaba Arthas

https://github.com/alibaba/arthas

參考文章

1、Plumbr OutOfMemoryError(推薦,含代碼示例)

2、GCeasy OutOfMemoryError

3、JVM 內(nèi)存結(jié)構(gòu)

作者:夏明(涯海)

創(chuàng)作日期:2019-07-15

專欄地址:【穩(wěn)定大于一切】

總結(jié)

以上是生活随笔為你收集整理的javaheapspace解决方案_高手总结的9种 OOM 常见原因及解决方案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。