蘇州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)題。
任何像內(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í)間的推移逐漸增加。
擁有良性垃圾回收機(jī)制的健康圖表
健康一段時(shí)間后,隨時(shí)間推移而泄露的圖表
引起內(nèi)存使用凸起、導(dǎo)致內(nèi)存溢出的內(nèi)存圖表
在我們了解導(dǎo)致使用率激增的內(nèi)存問(wèn)題的本質(zhì)之后,基于從對(duì)分析中得到的推斷,下面的這些方法或許可以用來(lái)避免遭遇內(nèi)存溢出的錯(cuò)誤。
修復(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ì)象。
增加內(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í)例嗎?
現(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)致的。希望你使用堆分析愉快!
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課程推薦:
配置應(yīng)用,為堆分析做準(zhǔn)備
原因分析
解決內(nèi)存問(wèn)題
堆分析
可疑點(diǎn) 2
檢查代碼
擴(kuò)展閱讀
免費(fèi)體驗(yàn)課開(kāi)班倒計(jì)時(shí)
稍后會(huì)有專業(yè)老師給您回電,請(qǐng)保持電話暢通
最新新聞
- 西安效果好的java大數(shù)據(jù)培訓(xùn)哪家教育機(jī)構(gòu)比較好
- 看這里,洛陽(yáng)前三Java應(yīng)用開(kāi)發(fā)培訓(xùn)班排名一覽表
- 看這里,洛陽(yáng)前三Java編程語(yǔ)言培訓(xùn)班有推薦嗎
- 盤(pán)點(diǎn)一下!洛陽(yáng)十大Java應(yīng)用開(kāi)發(fā)培訓(xùn)機(jī)構(gòu)名單公布
- 咸陽(yáng)盤(pán)點(diǎn)前五java程序員培訓(xùn)一般多少錢(qián)
- 陜西西安口碑不錯(cuò)的互聯(lián)網(wǎng)架構(gòu)師培訓(xùn)機(jī)構(gòu)哪家強(qiáng)
- 熱推!杭州前五Java應(yīng)用開(kāi)發(fā)培訓(xùn)班匯總
- 舉薦!杭州前十口碑好的java培訓(xùn)班 收費(fèi)標(biāo)準(zhǔn)
- 看這里,上海口碑好的Java應(yīng)用開(kāi)發(fā)培訓(xùn)機(jī)構(gòu)一覽表
- 甄選!上海徐匯區(qū)java技能培訓(xùn)費(fèi)用