亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java開發(fā)中的OOM內存溢出問題詳解

 更新時間:2023年08月22日 09:40:42   作者:王廷云的博客  
這篇文章主要介紹了Java開發(fā)中的OOM內存溢出問題詳解,OOM,全稱?Out?Of?Memory,意思是內存耗盡或內存溢出,當JVM因為沒有足夠的內存來為對象分配空間并且垃圾回收器也已經沒有空間可回收時,就會拋出這個?error,需要的朋友可以參考下

一、OOM 簡介

1、什么是 OOM ?

OOM,全稱 Out Of Memory,意思是內存耗盡或內存溢出。

對應Java 程序拋出的錯為 java.lang.OutOfMemoryError ,這個錯誤在官方的解釋如下:

Thrown when the Java Virtual Machine cannot allocate an object because it is out of memory, and no more memory could be made available by the garbage collector.

意思就是說,當 JVM 因為沒有足夠的內存來為對象分配空間并且垃圾回收器也已經沒有空間可回收時,就會拋出這個 error(注意:這錯誤并非 exception,因為這個問題已經嚴重到不足以被應用處理)。

二、OOM 原因分析

1、發(fā)生 OOM 的原因

出現(xiàn)了 OOM 就表示內存耗盡了,出現(xiàn)這種情況主要原因為:

  • 內存分配不足:分配給 JVM 虛擬機的內存過少(這是在啟動時設置JVM參數(shù)來指定);
  • 應用程序問題:應用使用內存過多,并且用完后沒有及時釋放造成浪費,此時就會造成內存泄露或者內存溢出。

內存泄露與溢出:

  • 內存泄露:申請使用完的內存沒有釋放,導致虛擬機不能再次使用該內存,此時就造成了內存泄露了;
  • 內存溢出:申請的內存超出了 JVM 能提供的內存大小,此時稱之為溢出。

2、OOM 的類型

在講解OOM類型時,我們需要了解一下 JAVA 虛擬機的內存區(qū)域:

  • 程序計數(shù)器:當前線程執(zhí)行的字節(jié)碼的行號指示器,線程私有;
  • JAVA虛擬機棧:Java方法執(zhí)行的內存模型,每個Java方法的執(zhí)行對應著一個棧幀的進棧和出棧的操作。
  • 本地方法棧:類似JAVA虛擬機棧 ,但是為 native 方法的運行提供內存環(huán)境。
  • JAVA堆:對象內存分配的地方,內存垃圾回收的主要區(qū)域,所有線程共享??煞譃樾律仙?。
  • 方法區(qū):用于存儲已經被JVM加載的類信息、常量、靜態(tài)變量、即時編譯器編譯后的代碼等數(shù)據(jù)。Hotspot 中的永久代。
  • 運行時常量池:方法區(qū)的一部分,存儲常量信息,如各種字面量、符號引用等。
  • 直接內存:并不是JVM運行時數(shù)據(jù)區(qū)的一部分, 可直接訪問的內存, 比如NIO會用到這部分。

除了程序計數(shù)器不會拋出OOM外,其他各個內存區(qū)域都可能會拋出OOM。

常見的OOM情況有以下三種:

  • java.lang.OutOfMemoryError: Java heap space :Java 堆內存溢出,此種情況最常見,一般由于內存泄露或者堆的大小設置不當引起。對于內存泄露,需要通過內存監(jiān)控軟件查找程序中的泄露代碼,而堆大小可以通過虛擬機參數(shù) -Xms,-Xmx 等修改。
  • java.lang.OutOfMemoryError: PermGen space :Java 永久代溢出,即方法區(qū)溢出了,一般出現(xiàn)在大量 Class 或者 jsp 頁面,或者采用 cglib 等反射機制的情況。因為上述情況會產生大量的 Class 信息存儲于方法區(qū)。此種情況可以通過更改方法區(qū)的大小來解決,使用類似 -XX:PermSize=64m -XX:MaxPermSize=256m 的形式修改。另外,過多的常量尤其是字符串也會導致方法區(qū)溢出。
  • java.lang.StackOverflowError :不會拋 OOM error,但也是比較常見的 Java 內存溢出。JAVA虛擬機棧溢出,一般是由于程序中存在死循環(huán)或者深度遞歸調用造成的,棧大小設置太小也會出現(xiàn)此種溢出。可以通過虛擬機參數(shù) -Xss 來設置棧的大小。

3、分析 OOM

分析 OOM,我們需要借助 Heap Dump 文件(堆轉儲文件),它是一個 Java 進程在某個時間點上的內存快照,在觸發(fā)快照的時候會保存 java 對象和類的信息。

要獲得 dump 文件,可以采用如下兩種方式:

  • 設置 JVM 參數(shù) -XX:+HeapDumpOnOutOfMemoryError :設定該參數(shù)后,當發(fā)生 OOM 時會自動 dump 出堆信息(需要JDK5以上版本)。
  • 使用JDK自帶的jmap命令: jmap -dump:format=b,file=heap.bin <pid> ,其中 pid 可以通過 jps 命令獲取。

dump 堆內存信息后,需要對 dump 文件進行分析,從而找到 OOM 的原因。常用的工具有:

mat(eclipse memory analyzer):基于eclipse RCP的內存分析工具。詳細信息參見://www.eclipse.org/mat,推薦使用該工具。

jhat:JDK 自帶的 java heap analyze tool,可以將堆中的對象以 html 的形式顯示出來,包括對象的數(shù)量,大小等等,并支持對象查詢語言OQL。分析相關的應用后,可以通過 //localhost:7000 來訪問分析結果。

上面兩種方式推薦使用 mat 而不推薦使用 jhat。因為在實際的排查過程中,一般是先在生產環(huán)境 dump 出文件來,然后拉到自己的開發(fā)機器上分析,所以,不如采用高級的分析工具 mat 來的高效。

其他工具:

ARMS (阿里云 APM 產品, 支持 OOM 異常關鍵字告警):https://help.aliyun.com/document_detail/42966.html;

Alibaba Arthas (阿里 Java 在線診斷工具 Arthas):https://github.com/alibaba/arth

三、OOM 解決方案

1、 Java heap space

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

產生的原因:

Java heap space 錯誤產生的常見原因可以分為以下幾類:

  • 請求創(chuàng)建一個超大對象,通常是一個大數(shù)組;
  • 超出預期的訪問量或數(shù)據(jù)量,通常是上游系統(tǒng)請求流量飆升,常見于各類促銷或秒殺活動,可以結合業(yè)務流量指標排查是否有尖狀峰值;
  • 過度使用終結器(Finalizer),該對象沒有立即被 GC;
  • 內存泄漏(Memory Leak),大量對象引用沒有釋放,JVM 無法對其自動回收,常見于使用了 File 等資源沒有回收。

解決方法:

針對大部分情況,通常只需要通過 -Xmx 參數(shù)調高 JVM 堆內存空間即可。如果仍然沒有解決,可以參考以下情況做進一步處理:

  • 如果是超大對象,可以檢查其合理性,比如是否一次性查詢了數(shù)據(jù)庫全部結果,而沒有做結果數(shù)限制;
  • 如果是業(yè)務峰值壓力,可以考慮添加機器資源,或者做限流降級;
  • 如果是內存泄漏,需要找到持有的對象,修改代碼設計,比如關閉沒有釋放的連接。

2、 GC overhead limit exceeded

當 Java 進程花費 98% 以上的時間執(zhí)行 GC,但只恢復了不到 2% 的內存,且該動作連續(xù)重復了 5 次,就會拋出 java.lang.OutOfMemoryError:GC overhead limit exceeded 錯誤。

簡單地說,就是應用程序已經基本耗盡了所有可用內存,GC 也無法回收。

此類問題的原因與解決方案跟 Java heap space 類似。

3、 Permgen space

該錯誤表示永久代 (Permanent Generation) 已用滿,通常是因為加載的 class 數(shù)目太多或體積太大。

永久代存儲對象主要包括:加載或緩存到內存中的 class 定義,包括類的名稱、字段、方法和字節(jié)碼;常量池;對象數(shù)組或類型數(shù)組所關聯(lián)的 class;JIT 編譯器優(yōu)化后的 class 信息。

PermGen 的使用量與加載到內存的 class 的數(shù)量和大小成正相關。

解決方法:

根據(jù) Permgen space 報錯的時機,可以采用不同的解決方案:

  • 程序啟動報錯,修改 -XX:MaxPermSize 啟動參數(shù),調大永久代空間。
  • 應用重新部署時報錯,很可能是沒有應用沒有重啟,導致加載了多份 class 信息,只需重啟 JVM 即可解決。
  • 運行時報錯,應用程序可能會動態(tài)創(chuàng)建大量 class,而這些 class 的生命周期很短暫,但是 JVM 默認不會卸載 class,可以設置 -XX:+CMSClassUnloadingEnabled 和 -XX:+UseConcMarkSweepGC 這兩個參數(shù)允許 JVM 卸載 class。

如果上述方法無法解決則需要通過 dump 文件逐一分析開銷最大的 classloader 和重復 class。

4、 Metaspace

JDK 1.8 使用 Metaspace 替換了永久代(Permanent Generation),該錯誤表示 Metaspace 已被用滿,通常是因為加載的 class 數(shù)目太多或體積太大。

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

5、 Unable to create new native thread

每個 Java 線程都需要占用一定的內存空間,當 JVM 向底層操作系統(tǒng)請求創(chuàng)建一個新的 native 線程時,如果沒有足夠的資源分配就會報此錯誤。

產生此錯誤的原因有:

  • 線程數(shù)超過操作系統(tǒng)最大線程數(shù) ulimit 限制;
  • 線程數(shù)超過 kernel.pid_max(只能重啟);
  • native 內存不足;

解決方法:

  • 升級配置,為機器提供更多的內存;
  • 降低 Java Heap Space 大小;
  • 修復應用程序的線程泄漏問題;
  • 限制線程池大?。?/li>
  • 使用 -Xss 參數(shù)減少線程棧的大?。?/li>
  • 調高 OS 層面的線程最大數(shù): 執(zhí)行 ulimia-a 查看最大線程數(shù)限制,使用 ulimit-u xxx 調整最大線程數(shù)限制。

6、 Out of swap space

該錯誤表示所有可用的虛擬內存已被耗盡。虛擬內存 (Virtual Memory) 由物理內存 (Physical Memory) 和交換空間 (Swap Space) 兩部分組成。

當運行時程序請求的虛擬內存溢出時就會報 Outof swap space? 錯誤。

常見原因:

  • 地址空間不足;
  • 物理內存已耗光;
  • 應用程序的本地內存泄漏(native leak),例如不斷申請本地內存,卻不釋放。
  • 執(zhí)行 jmap-histo:live 命令,強制執(zhí)行 Full GC; 如果幾次執(zhí)行后內存明顯下降,則基本確認為 Direct ByteBuffer 問題。

解決方法:

  • 升級地址空間為 64 bit;
  • 使用 Arthas 檢查是否為 Inflater/Deflater 解壓縮問題,如果是,則顯式調用 end 方法。
  • Direct ByteBuffer 問題可以通過啟動參數(shù) -XX:MaxDirectMemorySize 調低閾值。
  • 升級服務器配置或隔離部署,避免爭用。

7、 Kill process or sacrifice child

有一種內核作業(yè) (Kernel Job) 名為 Out of Memory Killer,它會在可用內存極低的情況下 殺死(kill)某些進程。

OOM Killer 會對所有進程進行打分,然后將評分較低的進程 殺死,具體的評分規(guī)則可以參考 Surviving the Linux OOM Killer。

不同于其他的 OOM 錯誤,Kill processor sacrifice child 錯誤不是由 JVM 層面觸發(fā)的,而是由操作系統(tǒng)層面觸發(fā)的。默認情況下,Linux 內核允許進程申請的內存總量大于系統(tǒng)可用內存,通過這種 “錯峰復用” 的方式可以更有效的利用系統(tǒng)資源。

然而,這種方式也會無可避免地帶來一定的 “超賣” 風險。例如某些進程持續(xù)占用系統(tǒng)內存,然后導致其他進程沒有可用內存。此時,系統(tǒng)將自動激活 OOM Killer,尋找評分低的進程,并將其 “殺死”,釋放內存資源。

解決方法:

  • 升級服務器配置 / 隔離部署,避免爭用。
  • OOM Killer 調優(yōu)。

8、 Requested array size exceeds VM limit

JVM 限制了數(shù)組的最大長度,該錯誤表示程序請求創(chuàng)建的數(shù)組超過最大長度限制。JVM 在為數(shù)組分配內存前,會檢查要分配的數(shù)據(jù)結構在系統(tǒng)中是否可尋址,通常為 Integer.MAX_VALUE - 2。

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

9、 Direct buffer memory

Java 允許應用程序通過 Direct ByteBuffer 直接訪問堆外內存,許多高性能程序通過 Direct ByteBuffer 結合內存映射文件 (Memory Mapped File) 實現(xiàn)高速 IO。

Direct ByteBuffer 的默認大小為 64 MB,一旦使用超出限制,就會拋出 Directbuffer memory 錯誤。

解決方案:

  • Java 只能通過 ByteBuffer.allocateDirect 方法使用 Direct ByteBuffer,因此,可以通過 Arthas 等在線診斷工具攔截該方法進行排查。
  • 檢查是否直接或間接使用了 NIO,如 netty,jetty 等。
  • 通過啟動參數(shù) -XX:MaxDirectMemorySize 調整 Direct ByteBuffer 的上限值。
  • 檢查 JVM 參數(shù)是否有 -XX:+DisableExplicitGC 選項,如果有就去掉,因為該參數(shù)會使 System.gc() 失效。
  • 檢查堆外內存使用代碼,確認是否存在內存泄漏; 或者通過反射調用 sun.misc.Cleaner 的 clean() 方法來主動釋放被 Direct ByteBuffer 持有的內存空間。
  • 內存容量確實不足,升級配置。

到此這篇關于Java開發(fā)中的OOM內存溢出問題詳解的文章就介紹到這了,更多相關Java中的OOM內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • MyBatis批量插入/修改/刪除MySql數(shù)據(jù)

    MyBatis批量插入/修改/刪除MySql數(shù)據(jù)

    這篇文章主要給大家介紹了關于MyBatis批量插入/修改/刪除MySql數(shù)據(jù)的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-05-05
  • java String.join()的使用小結

    java String.join()的使用小結

    String.join()是Java 8引入的一個實用方法,用于將多個字符串按照指定分隔符連接成一個字符串,本文主要介紹了java String.join()的使用小結,感興趣的可以了解一下
    2025-03-03
  • 解決jhipster修改jdl生成的實體類報錯:liquibase.exception.ValidationFailedException: Validation Failed

    解決jhipster修改jdl生成的實體類報錯:liquibase.exception.ValidationFailed

    這篇文章主要介紹了解決jhipster修改jdl生成的實體類報錯:liquibase.exception.ValidationFailedException: Validation Failed問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • java利用DFA算法實現(xiàn)敏感詞過濾功能

    java利用DFA算法實現(xiàn)敏感詞過濾功能

    在最近的開發(fā)中遇到了敏感詞過濾,便去網(wǎng)上查閱了很多敏感詞過濾的資料,在這里也和大家分享一下自己的理解。下面這篇文章主要給大家介紹了關于java利用DFA算法實現(xiàn)敏感詞過濾功能的相關資料,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-06-06
  • 淺談JVM內存溢出原因和解決思路

    淺談JVM內存溢出原因和解決思路

    本文主要介紹了淺談JVM內存溢出原因和解決思路,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • SpringBoot實現(xiàn)發(fā)送短信的示例代碼

    SpringBoot實現(xiàn)發(fā)送短信的示例代碼

    這篇文章主要介紹了SpringBoot實現(xiàn)發(fā)送短信的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-04-04
  • Java運行時環(huán)境之ClassLoader類加載機制詳解

    Java運行時環(huán)境之ClassLoader類加載機制詳解

    這篇文章主要給大家介紹了關于Java運行時環(huán)境之ClassLoader類加載機制的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-01-01
  • 基于java.lang.IllegalArgumentException異常報錯問題及解決

    基于java.lang.IllegalArgumentException異常報錯問題及解決

    這篇文章主要介紹了基于java.lang.IllegalArgumentException異常報錯問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • 淺析Java如何實現(xiàn)動態(tài)線程池的任務編排

    淺析Java如何實現(xiàn)動態(tài)線程池的任務編排

    動態(tài)線程池是在程序運行期間,動態(tài)調整線程池參數(shù)而無需重啟程序的技術,那么如何在動態(tài)線程池中進行任務編排呢,下面小編就來和大家詳細介紹一下吧
    2025-09-09
  • 在deepin上如何使用Fleet開發(fā)SpringBoot?3.0.0項目

    在deepin上如何使用Fleet開發(fā)SpringBoot?3.0.0項目

    這篇文章主要介紹了在deepin上使用Fleet開發(fā)SpringBoot?3.0.0項目的過程,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-09-09

最新評論