蘇州培訓(xùn)網(wǎng) > 蘇州JAVA培訓(xùn)機(jī)構(gòu) > 三網(wǎng)IT
首頁(yè) 培訓(xùn)網(wǎng) 最新資訊 熱門(mén)問(wèn)答

三網(wǎng)IT

免費(fèi)試聽(tīng) 13013833891

您當(dāng)前的位置: 資訊首頁(yè) > JAVA培訓(xùn)資訊 > 蘇州JAVA前端開(kāi)發(fā)培訓(xùn)?

蘇州JAVA前端開(kāi)發(fā)培訓(xùn)?

來(lái)源:教育聯(lián)展網(wǎng)    編輯:佚名    發(fā)布時(shí)間:2018-04-08

蘇州JAVA前端開(kāi)發(fā)培訓(xùn)

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

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

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

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

  • 當(dāng)內(nèi)存溢出時(shí),獲取到 Java 進(jìn)程中的堆轉(zhuǎn)儲(chǔ)。

  • 明白應(yīng)用程序正在遭遇的內(nèi)存問(wèn)題的類(lèi)型。

  • 使用一個(gè)堆分析器,可以使用 Eclipse MAT 這個(gè)優(yōu)秀的開(kāi)源項(xiàng)目來(lái)分析內(nèi)存溢出的問(wèn)題。

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

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

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

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


原因分析

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

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

  • 尖峰狀:這種類(lèi)型的內(nèi)存溢出在某種類(lèi)型的加載上會(huì)是比較激烈的。當(dāng) JVM 分配內(nèi)存給 20 個(gè)用戶時(shí),應(yīng)用程序可以正常運(yùn)行。但是,如果到第 100 個(gè)用戶時(shí)可能會(huì)遭遇到內(nèi)存峰值,從而導(dǎo)致內(nèi)存溢出。有兩種可能的辦法去解決這個(gè)問(wèn)題。

  • 泄露:由于某些編程問(wèn)題,內(nèi)存使用隨著時(shí)間的推移逐漸增加。

蘇州JAVA前端開(kāi)發(fā)培訓(xùn)

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

     蘇州JAVA前端開(kāi)發(fā)培訓(xùn)哪家好

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

          蘇州JAVA前端開(kāi)發(fā)培訓(xùn)如何


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

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

解決內(nèi)存問(wèn)題

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

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

堆分析

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

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

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

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

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

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

4. 上面的餅圖**聚合擁有**高內(nèi)存引用(本身內(nèi)存和總內(nèi)存)的對(duì)象來(lái)展示 3 個(gè)問(wèn)題嫌疑人。

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


可疑點(diǎn) 1

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

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

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

本質(zhì)上,開(kāi)發(fā)者編寫(xiě)了一些定制化的終結(jié)器去釋放一個(gè)實(shí)例的資源。這些由終結(jié)器收集的實(shí)例不在 JVM 使用單獨(dú)隊(duì)列的垃圾回收算法的范圍之內(nèi)。實(shí)際上,這種途徑比起垃圾回收機(jī)制的清理路徑更長(zhǎng)。所以現(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)在,讓我們打開(kāi)在 MAT 頂部的工具按鈕下面的 Dominator 視圖。我們會(huì)看到所有的列出的類(lèi)實(shí)例,經(jīng)由 MAT 解析展示出有效的堆存儲(chǔ)。

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

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

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

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

檢查代碼

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

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


擴(kuò)展閱讀

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

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

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

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

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

一些對(duì)象的主要集合,比如某一特定類(lèi)的所有對(duì)象、或是由某一特定類(lèi)加載器加載的所有類(lèi)的所有對(duì)象、或僅僅是一些任意的對(duì)象,它們的保留集是如果那些主要集的所有對(duì)象變得不可接近時(shí)所釋放的對(duì)象集。

保留集包括這些對(duì)象和僅**這些對(duì)象才能獲取的其它對(duì)象。保留集的大小是包含在保留集中的所有對(duì)象的堆的大小。




咨詢聯(lián)系方式:13861302024(楊老師)或者QQ:2589245390 還可以直接在線咨詢

更多JAVA課程推薦:

蘇州JAVA培訓(xùn)網(wǎng)

蘇州JAVA軟件培訓(xùn)

蘇州三網(wǎng)IT教育培訓(xùn)

蘇州其然軟件開(kāi)發(fā)培訓(xùn)

上一篇:蘇州JAVA開(kāi)發(fā)應(yīng)用培訓(xùn)? 下一篇:蘇州2018年JAVA發(fā)展前景?
蘇州JAVA

免費(fèi)體驗(yàn)課開(kāi)班倒計(jì)時(shí)

11: 41: 09

稍后會(huì)有專業(yè)老師給您回電,請(qǐng)保持電話暢通

咨詢電話:13013833891

校區(qū)導(dǎo)航

1個(gè)校區(qū)

蘇州三網(wǎng)IT教育
推薦機(jī)構(gòu) 全國(guó)分站 更多課程

今日已有25人申請(qǐng),本月限額500

申請(qǐng)?jiān)嚶?tīng)名額

已有10254人申請(qǐng)免費(fèi)試聽(tīng)

01電話咨詢 | 13013833891

QQ:
加盟合作:0755-83654572