最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java 堆內(nèi)存溢出原因分析

 更新時間:2019年06月13日 09:28:46   作者:dreamanzhao, 溪邊九節(jié)  
這篇文章主要介紹了Java 堆內(nèi)存溢出原因分析,任何使用過基于 Java 的企業(yè)級后端應(yīng)用的軟件開發(fā)者都會遇到過這種報錯,java.lang.OutOfMemoryError:Java heap space。,需要的朋友可以參考下

前言

任何使用過基于 Java 的企業(yè)級后端應(yīng)用的軟件開發(fā)者都會遇到過這種低劣、奇怪的報錯,這些報錯來自于用戶或是測試工程師: java.lang.OutOfMemoryError:Java heap space。

為了弄清楚問題,我們必須返回到算法復(fù)雜性的計算機(jī)科學(xué)基礎(chǔ),尤其是“空間”復(fù)雜性。如果我們回憶,每一個應(yīng)用都有一個最壞情況特征。具體來說,在存儲維度方面,超過推薦的存儲將會被分配到應(yīng)用程序上,這是不可預(yù)測但尖銳的問題。這導(dǎo)致了堆內(nèi)存的過度使用,因此出現(xiàn)了"內(nèi)存不夠"的情況。

這種特定情況最糟糕的部分是應(yīng)用程序不能修復(fù),并且將崩潰。任何重啟應(yīng)用的嘗試 - 甚至使用最大內(nèi)存(-Xmx option)- 都不是長久之計。如果不明白什么導(dǎo)致了堆使用的膨脹或突出,內(nèi)存使用穩(wěn)定性(即應(yīng)用穩(wěn)定性)就不能保障。于是,什么才是更有效的理解關(guān)于內(nèi)存的編程問題的途徑?當(dāng)內(nèi)存溢出時,明白應(yīng)用程序的內(nèi)存堆和分布情況才能回答這個問題。

在這一前提下,我們將聚焦以下方面:

  • 當(dāng)內(nèi)存溢出時,獲取到 Java 進(jìn)程中的堆轉(zhuǎn)儲。
  • 明白應(yīng)用程序正在遭遇的內(nèi)存問題的類型。
  • 使用一個堆分析器,可以使用 Eclipse MAT 這個優(yōu)秀的開源項目來分析內(nèi)存溢出的問題。

配置應(yīng)用,為堆分析做準(zhǔn)備

任何像內(nèi)存溢出這種非確定性的、時有時無的問題對于事后的分析都是一個挑戰(zhàn)。所以,最好的處理內(nèi)存溢出的方法是讓 JVM 虛擬機(jī)轉(zhuǎn)儲一份 JVM 虛擬機(jī)內(nèi)存狀態(tài)的堆文件。

Sun HotSpot JVM 有一種方法可以引導(dǎo) JVM 轉(zhuǎn)儲內(nèi)存溢出時的堆狀態(tài)到一個文件中。其標(biāo)準(zhǔn)格式為 .hprof 。所以,為了實(shí)現(xiàn)這種操作,向 JVM 啟動項中添加 XX:+HeapDumpOnOutOfMemoryError 。因?yàn)閮?nèi)存溢出可能經(jīng)過很長一段時間才會發(fā)生,向生產(chǎn)系統(tǒng)增加這一選項也是必須的。

如果堆轉(zhuǎn)儲 .hprof 文件必須被寫在一個特定的文件系統(tǒng)位置,那么就添加目錄途徑到 XX:HeapDumpPath 。只需確保該應(yīng)用對于指定目錄途徑始終擁有寫入權(quán)限。

原因分析

101:了解內(nèi)存溢出錯誤的本質(zhì)

當(dāng)嘗試去評估和了解一個內(nèi)存溢出錯誤時,最先做的事情應(yīng)該是觀察內(nèi)存增長特征。根據(jù)情況做出可能性的評估:

  • 尖峰狀:這種類型的內(nèi)存溢出在某種類型的加載上會是比較激烈的。當(dāng) JVM 分配內(nèi)存給 20 個用戶時,應(yīng)用程序可以正常運(yùn)行。但是,如果到第 100 個用戶時可能會遭遇到內(nèi)存峰值,從而導(dǎo)致內(nèi)存溢出。有兩種可能的辦法去解決這個問題。
  • 泄露:由于某些編程問題,內(nèi)存使用隨著時間的推移逐漸增加。

擁有良性垃圾回收機(jī)制的健康圖表

健康一段時間后,隨時間推移而泄露的圖表

引起內(nèi)存使用凸起、導(dǎo)致內(nèi)存溢出的內(nèi)存圖表

在我們了解導(dǎo)致使用率激增的內(nèi)存問題的本質(zhì)之后,基于從對分析中得到的推斷,下面的這些方法或許可以用來避免遭遇內(nèi)存溢出的錯誤。

解決內(nèi)存問題

1.修復(fù)引起內(nèi)存溢出的代碼:由于應(yīng)用在某段時間內(nèi)增量添加了一個對象而沒有清除其引用(來自正在運(yùn)行的應(yīng)用程序的對象引用),導(dǎo)致不得不修復(fù)程序錯誤。例如,這一錯誤可能是插入了一個哈希表, 其中的業(yè)務(wù)對象會逐漸增加,然而業(yè)務(wù)邏輯和事務(wù)在完成之后并沒有刪除這些對象。

2.增加內(nèi)存最大值作為一種修復(fù)方法。在了解了運(yùn)行內(nèi)存特征和堆之后,可能必須增加分配的最大堆內(nèi)存來避免再次發(fā)生內(nèi)存溢出,因?yàn)橥扑]的最大內(nèi)存值不能夠滿足應(yīng)用程序的穩(wěn)定性。所以,應(yīng)用程序可能不得不基于堆分析器的評估,將 Java -Xmx 的 flag 信息更新成一個更高值后再來運(yùn)行。

堆分析

下面我們將詳細(xì)分析如何使用一個堆分析工具來分析堆轉(zhuǎn)儲。在示例中,將使用到 Eclipse 基金會的開源工具 MAT 。

使用 MAT 進(jìn)行堆分析

是時候進(jìn)行深入探討了。我們將通過一系列的步驟,幫助探索在 MAT 中的不同表現(xiàn)和視圖,以獲取一個堆內(nèi)存溢出的示例并思考分析。

1. 打開內(nèi)存溢出錯誤發(fā)生時產(chǎn)生的 .hprof 堆文件。確保復(fù)制轉(zhuǎn)儲文件到一個專門的文件夾下,因?yàn)?MAT 會創(chuàng)建許多索引文件:文件 -> 打開

2. 打開轉(zhuǎn)儲文件,有內(nèi)存泄漏嫌疑報告和組件報告的選項。選擇運(yùn)行泄漏嫌疑報告。

3. 泄漏嫌疑表打開后,在預(yù)覽窗口的餅狀圖會展示在每個對象基礎(chǔ)上保留內(nèi)存的分布情況。它顯示了內(nèi)存中的最大對象(擁有最高保留內(nèi)存的對象 —— 累積的內(nèi)存和引用的對象)。

4. 上面的餅圖通過聚合擁有最高內(nèi)存引用(本身內(nèi)存和總內(nèi)存)的對象來展示 3 個問題嫌疑人。

讓我們逐一分情況查看,評估它是否是內(nèi)存溢出錯誤的根本原因。

可疑點(diǎn) 1

由 “<system class loader>” 加載的 454,570 個 “java.lang.ref.Finalizer” 實(shí)例占用了 790,205,576(47.96%)個字節(jié)。

這就是告訴我們有 454,570 個 JVM finalizer(終結(jié)器)實(shí)例占據(jù)了分配的應(yīng)用內(nèi)存的近 50 %。

假設(shè)讀者知道 Java Finalizer 是做什么的,上面的信息會讓我們明白什么呢?

本質(zhì)上,開發(fā)者編寫了一些定制化的終結(jié)器去釋放一個實(shí)例的資源。這些由終結(jié)器收集的實(shí)例不在 JVM 使用單獨(dú)隊列的垃圾回收算法的范圍之內(nèi)。實(shí)際上,這種途徑比起垃圾回收機(jī)制的清理路徑更長。所以現(xiàn)在我們應(yīng)該努力搞清楚這些終結(jié)器到底終結(jié)了什么?

也或許是可疑點(diǎn) 2 ,占據(jù)了 20% 的 sun.security.ssl.SSLSocketImpl 。我們能確認(rèn)是否這些就是要被終結(jié)器終結(jié)的實(shí)例嗎?

可疑點(diǎn) 2

現(xiàn)在,讓我們打開在 MAT 頂部的工具按鈕下面的 Dominator 視圖。我們會看到所有的列出的類實(shí)例,經(jīng)由 MAT 解析展示出有效的堆存儲。

下一步,在 Dominator 視圖,我們嘗試?yán)斫?java.lang.Finalizer 和 sun.security.ssl.SSLSocketImpl 之間的關(guān)系。我們右鍵點(diǎn)擊 sun.security.ssl.SSLSocketImpl 這一列,打開 GC Roots -> exclude soft/weak references。

現(xiàn)在,MAT 將會開始繪制內(nèi)存的圖表來顯示 GC root 的路徑以及它所對應(yīng)的實(shí)例引用。這會被顯示在另外一個頁面上,顯示的引用如下:

如上面引用鏈顯示,實(shí)例 SSLSocketImpl 來自于 java.lang.ref.Finalizer,整個 SSLSocketImpl 實(shí)例大約占用了 88k。我們還注意到 finalizer 鏈?zhǔn)且粋€針鏈表數(shù)據(jù)結(jié)構(gòu)它指向下一個實(shí)例。

推論:在這一點(diǎn)上,我們有一個明確的感覺,Java finalizer 試圖在收集 SSLSocketImpl 對象。為了解釋為什么還有很多信息沒有被收集到,我開始檢查代碼。

檢查代碼

代碼檢查需要查看是不是由 socket 套接字被關(guān)閉導(dǎo)致的。在這種情況下,它顯示與 I/O 相關(guān)的所有流,需要被正確地關(guān)閉。在一點(diǎn)上,我們懷疑 JVM 是始作俑者。實(shí)際上,在 Open JDK 6.0.XX 的 GC(垃圾收集器)上的代碼中有一個 BUG。

我希望這篇文章給你一個模式來分析 Java 應(yīng)用中的錯誤是由堆存儲還是內(nèi)部問題導(dǎo)致的。希望你使用堆分析愉快!

Shallow heap (淺堆) vs. Retained Heap (保留堆)

淺堆是一個對象消耗的內(nèi)存。根據(jù)情況,一個對象需要 32 位或 64 位(取決于其操作系統(tǒng)架構(gòu)),對于整型為 4 字節(jié),對于 Long 型為 8 字節(jié)等等。依據(jù)堆轉(zhuǎn)儲格式,其內(nèi)存大小(比如,向 8 對齊)或許適應(yīng)于更好地塑造虛擬機(jī)的真實(shí)消耗。

X 的保留集合是當(dāng) X 被垃圾回收時,那些將要被移除的對象集合。

X 的保留堆是在 X 的保留集合中所有對象的淺堆之和,也就是 X 存留的內(nèi)存。

總體講,一個對象的淺堆就是其在堆中的大小。同一個對象的保留大小就是當(dāng)對象被垃圾回收時堆內(nèi)存的總量。

一些對象的主要集合,比如某一特定類的所有對象、或是由某一特定類加載器加載的所有類的所有對象、或僅僅是一些任意的對象,它們的保留集是如果那些主要集的所有對象變得不可接近時所釋放的對象集。保留集包括這些對象和僅通過這些對象才能獲取的其它對象。保留集的大小是包含在保留集中的所有對象的堆的大小。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 解決啟用 Spring-Cloud-OpenFeign 配置可刷新項目無法啟動的問題

    解決啟用 Spring-Cloud-OpenFeign 配置可刷新項目無法啟動的問題

    這篇文章主要介紹了解決啟用 Spring-Cloud-OpenFeign 配置可刷新項目無法啟動的問題,本文重點(diǎn)給大家介紹Spring-Cloud-OpenFeign的原理及問題解決方法,需要的朋友可以參考下
    2021-10-10
  • Hibernate緩存機(jī)制實(shí)例代碼解析

    Hibernate緩存機(jī)制實(shí)例代碼解析

    這篇文章主要介紹了Hibernate緩存機(jī)制實(shí)例代碼解析,介紹了查詢緩存,一級二級緩存等內(nèi)容,分享了相關(guān)代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下
    2018-02-02
  • 快速解決code唯一碼(java)的簡便方法

    快速解決code唯一碼(java)的簡便方法

    下面小編就為大家?guī)硪黄焖俳鉀Qcode唯一碼(java)的簡便方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-08-08
  • Springmvc 4.x利用@ResponseBody返回Json數(shù)據(jù)的方法

    Springmvc 4.x利用@ResponseBody返回Json數(shù)據(jù)的方法

    這篇文章主要介紹了Springmvc 4.x利用@ResponseBody返回Json數(shù)據(jù)的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-04-04
  • Java 爬蟲服務(wù)器被屏蔽的解決方案

    Java 爬蟲服務(wù)器被屏蔽的解決方案

    這篇文章主要介紹了Java 爬蟲服務(wù)器被屏蔽的解決方案,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-10-10
  • SpringCloudGateway使用Skywalking時日志打印traceId解析

    SpringCloudGateway使用Skywalking時日志打印traceId解析

    這篇文章主要為大家介紹了SpringCloudGateway使用Skywalking時日志打印traceId解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • Java反射機(jī)制深入理解

    Java反射機(jī)制深入理解

    這篇文章主要介紹了Java反射機(jī)制深入理解的相關(guān)資料,希望通過本文大家能理解這部分內(nèi)容,需要的朋友可以參考下
    2017-09-09
  • Java多線程中關(guān)于join方法的使用實(shí)例解析

    Java多線程中關(guān)于join方法的使用實(shí)例解析

    本文通過實(shí)例代碼給大家實(shí)例介紹了Java多線程中關(guān)于join方法的使用,非常不錯,具有參考借鑒價值,需要的朋友參考下
    2017-01-01
  • 超詳細(xì)的Java 問題排查工具單

    超詳細(xì)的Java 問題排查工具單

    這篇文章主要介紹了超詳細(xì)的Java 問題排查工具單,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • Java中Stringbuild,Date和Calendar類的用法詳解

    Java中Stringbuild,Date和Calendar類的用法詳解

    這篇文章主要為大家詳細(xì)介紹了Java中Stringbuild、Date和Calendar類的用法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下
    2023-04-04

最新評論

修水县| 雷山县| 通江县| 乌鲁木齐县| 大关县| 闵行区| 临夏县| 大埔县| 沙湾县| 南丰县| 常德市| 彭州市| 工布江达县| 洛隆县| 马鞍山市| 鄂温| 白朗县| 富平县| 五莲县| 鄱阳县| 额济纳旗| 吉水县| 彭泽县| 涿鹿县| 图木舒克市| 呼和浩特市| 洛浦县| 营山县| 霍邱县| 沈阳市| 眉山市| 达尔| 周宁县| 拉孜县| 承德市| 隆子县| 收藏| 海伦市| 武隆县| 兴隆县| 金坛市|