您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)生產(chǎn)環(huán)境JVM內(nèi)存溢出的示分析,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。
如果我們所在公司的業(yè)務(wù)量比較大,在生產(chǎn)環(huán)境經(jīng)常會(huì)出現(xiàn)JVM內(nèi)存溢出的現(xiàn)象,那我們?cè)撊绾慰焖夙憫?yīng),快速定位,快速恢復(fù)問(wèn)題呢?
通過(guò)一個(gè)線上環(huán)境JVM內(nèi)存溢出的案例向大家介紹一下處理思路與分析方法。
案例:架構(gòu)組接到某項(xiàng)目組反饋,Zabbix監(jiān)控上顯示JMX不可用,請(qǐng)求協(xié)助處理。
分析思路:
JMX不可用,往往是由于垃圾回收時(shí)間停頓時(shí)間過(guò)長(zhǎng)、內(nèi)存溢出等問(wèn)題引起的。
線上故障分析的原則是首先要采取措施快速恢復(fù)故障對(duì)業(yè)務(wù)的影響,然后才是采集信息、分析定位問(wèn)題,并最終給出解決辦法。
具體分析過(guò)程如下。
通常線上的故障會(huì)對(duì)業(yè)務(wù)造成重大影響,影響用戶體驗(yàn),故如果線上服務(wù)器出現(xiàn)故障,應(yīng)規(guī)避對(duì)業(yè)務(wù)造成影響,但不能簡(jiǎn)單的重啟服務(wù)器,因?yàn)樾枰M可能保留現(xiàn)場(chǎng),為后續(xù)的問(wèn)題分析打下基礎(chǔ)。
那我們?nèi)绾慰焖僖?guī)避對(duì)業(yè)務(wù)的影響,并能保留現(xiàn)場(chǎng)呢?
通常的做法是隔離故障服務(wù)器。
通常線上服務(wù)器是集群部署,一個(gè)好的分布式負(fù)載方案會(huì)自動(dòng)剔除故障的機(jī)器,從而實(shí)現(xiàn)高可用架構(gòu),但如果未被剔除,則需要運(yùn)維人員將故障服務(wù)器進(jìn)行剔除,保留現(xiàn)場(chǎng)進(jìn)行分析。
發(fā)生內(nèi)存泄露,通常情況下是由于代碼的原因造成的,一般無(wú)法立即對(duì)代碼進(jìn)行修復(fù),很容易會(huì)發(fā)送連鎖反應(yīng)造成應(yīng)用服務(wù)器一臺(tái)一臺(tái)接連宕機(jī),故障面積會(huì)慢慢擴(kuò)大,針對(duì)此種情況,應(yīng)快速定位發(fā)生內(nèi)存泄露的原因,將該服務(wù)進(jìn)行降級(jí),避免對(duì)其他服務(wù)造成影響。最簡(jiǎn)單的降級(jí)方法是根據(jù)F5(Nginx)轉(zhuǎn)發(fā)策略,對(duì)該功能定向到一個(gè)單獨(dú)的集群,與其他流量進(jìn)行隔離,確保其他業(yè)務(wù)不受牽連,給故障排查、解決提供寶貴的緩沖時(shí)間。
首先可以通過(guò)查看日志,確定是哪種內(nèi)存溢出,堆內(nèi)存溢出可發(fā)生的地方:Java heap space(堆空間)、perm space(持久代)。
收集Dump文件有兩種方式:
設(shè)置JVM啟動(dòng)參數(shù)
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/opt/jvmdump
在每次發(fā)生內(nèi)存溢出時(shí),JVM會(huì)自動(dòng)將堆轉(zhuǎn)儲(chǔ),dump文件存放在-XX:HeapDumpPath指定的路徑下。
使用jmap命令收集
通過(guò)jmap -dump:live,format=b,file=/opt/jvm/dump.hprof pid。
在獲取Dump文件后,可以使用工具M(jìn)AT(MemoryAnalyzer)進(jìn)行分析,該工具大家可以通過(guò)百度自行下載。
使用MAT打開(kāi)Dump文件后,首頁(yè)截圖如下:
工具按鈕介紹:
:直方圖視圖,將堆中所有的內(nèi)存消耗情況統(tǒng)計(jì)出來(lái),其如圖所示:
:內(nèi)存使用樹(shù)狀結(jié)構(gòu),以線程為維度,樹(shù)狀形式展開(kāi),如圖所示:
線程棧,其截圖如下:
根據(jù)該圖,可以明確,堆的總大小為1.9G,被4個(gè)線程全部占據(jù),導(dǎo)致其他線程無(wú)法再申請(qǐng)資源,拋出堆內(nèi)存溢出錯(cuò)誤。
接下來(lái),我通常的做法是直接去看這個(gè)視圖(以線程為基本維度,查找線程中占用內(nèi)存的對(duì)象),為后續(xù)定位排查提供必要的依據(jù)。
從上面的截圖中可以得出如下關(guān)鍵信息點(diǎn):
org.apache.ibatis.executor.result.DefaultResultHandler內(nèi)部持有一個(gè)List,其原始為java.util.HashMap,從這個(gè)類基本可以看出是與數(shù)據(jù)庫(kù)的查詢相關(guān),對(duì)數(shù)據(jù)庫(kù)返回結(jié)果的解碼并組織成HashMap。
這個(gè)List中的元素總共有146033個(gè),初步可以判斷出是在一次查詢中從數(shù)據(jù)庫(kù)中一次查詢出了太多數(shù)據(jù),造成了內(nèi)存溢出。
由于SQL查詢代碼中,是用HashMap來(lái)接收數(shù)據(jù)庫(kù)中的返回字段,無(wú)法一時(shí)間看出是那個(gè)查詢,那我們能不能精確找到是哪一個(gè)查詢,哪一行代碼,甚至與哪一條SQL語(yǔ)句呢?
答案是可以的,我們可以從視圖一探究竟。
溫馨提示:
視圖使用技巧:展開(kāi)技巧:沿著使用率最高的項(xiàng)一層一層進(jìn)行展開(kāi),直至發(fā)現(xiàn)具體占用內(nèi)存的對(duì)象。
接下來(lái)我們從 視圖去尋找是哪個(gè)方法,哪條SQL語(yǔ)句觸發(fā)的。
具體方法:首先完全展開(kāi)一個(gè)線程,從展開(kāi)圖的底部向上尋找:
其線程的入口(控制層代碼)
繼續(xù)往上查找,要找到SQL語(yǔ)句,應(yīng)該找到Mybatis處理結(jié)果集相關(guān)的類,如圖所示:
然后展開(kāi)boundSql即能找到SQL語(yǔ)句:
然后鼠標(biāo)可以放在SQL屬性中,右鍵,可以將SQL語(yǔ)句復(fù)制出來(lái)。
由于這里涉及到公司的代碼機(jī)密,故在這里不貼出具體的SQL語(yǔ)句。
這里根據(jù)后面的分析,原來(lái)是在做導(dǎo)出功能的時(shí)候,沒(méi)有使用分頁(yè)對(duì)數(shù)據(jù)進(jìn)行分頁(yè)查詢,分頁(yè)寫(xiě)入Excel文件,而是一次將全部數(shù)據(jù)查詢,導(dǎo)致導(dǎo)出功能如果并發(fā)數(shù)超過(guò)4個(gè)時(shí),就會(huì)將所有內(nèi)存耗盡。
解決方案:
首先在運(yùn)維層面將該請(qǐng)求導(dǎo)入到指定的一臺(tái)服務(wù)器上,是導(dǎo)出任務(wù)與其他任務(wù)進(jìn)行隔離,避免對(duì)其他重要服務(wù)造成影響。
項(xiàng)目組對(duì)其代碼進(jìn)行修復(fù),可以使用分頁(yè)查數(shù)據(jù),然后分配寫(xiě)入Excel。
關(guān)于生產(chǎn)環(huán)境JVM內(nèi)存溢出的示分析就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。