-
這里我們創(chuàng)建一個(gè)springboot項(xiàng)目, 然后隨便寫一個(gè)contoller, 在這個(gè)controller中定義一個(gè)List集合, 然后再初始化的時(shí)候讓集合中10萬個(gè)字符串, 然后部署并啟動(dòng)項(xiàng)目(這里為了貼近實(shí)戰(zhàn), 我是在centos中啟動(dòng)的項(xiàng)目)
-
進(jìn)入系統(tǒng), 使用top命令顯示系統(tǒng)中的進(jìn)程信息, 然后點(diǎn)擊H(大寫), 以內(nèi)存排序
這時(shí)我們看到, Java程序占用了5.5%的內(nèi)存
前面VIRT列表示的是java申請(qǐng)了多少內(nèi)存, RES表示實(shí)際使用了多少內(nèi)存 這里的單位是k
在這里主要是看一下概率情況, 同時(shí)拿到j(luò)ava程序的進(jìn)程編號(hào)
-
jdk為我們提供了jmap工具, 這個(gè)工具可以幫助我們掃描java進(jìn)行當(dāng)前的內(nèi)存情況
jmap的功能很多, 這里我們主要使用這個(gè)工具查看占用內(nèi)存最多的類型是什么
#?這里稍微解釋一下, | 的作用是拼接多個(gè)命令, |后面的命令利用前面的命令的執(zhí)行結(jié)果繼續(xù)執(zhí)行 jmap -histo:live 2249762 | head -20
num : 表示行號(hào), #instances 表示jvm中總共有這個(gè)數(shù)量的實(shí)例對(duì)象 #bytes表示這些實(shí)例對(duì)象總共占用了多少內(nèi)存(單位byte)
我們看到, jvm中總共有124240個(gè)字符串對(duì)象, 顯然不太合理
到這里, 我們其實(shí)僅僅能知道jvm中出現(xiàn)了大量不正常的字符串對(duì)象, 至于這些字符串在什么位置, 什么原因產(chǎn)生的還是一無所知
-
接下來, 我們需要具體看看是哪些字符串占用了內(nèi)存, 并且找出在引用關(guān)系, 看看是哪些對(duì)象在使用這些字符串
jmap智能粗略的分析內(nèi)存問題, 如果想要更細(xì)致的分析內(nèi)存,比如說分析對(duì)象之間的引用關(guān)系, 可以使用jhat工具
這個(gè)工具就需要們先將jvm內(nèi)存詳細(xì)信息導(dǎo)出到一個(gè)文件中,在使用jhat分析
使用 jmap -dump:live,file=heap.bin 進(jìn)程編號(hào) 命令, 將jvm內(nèi)存導(dǎo)出到一個(gè)heap.bin文件中
#?導(dǎo)出jvm結(jié)構(gòu) jmap -dump:live,file=heap.bin 2254420
#?使用jhat分析文件, jhat回啟動(dòng)一個(gè)服務(wù)器, 讓我們可以在網(wǎng)頁(yè)上查看信息, 默認(rèn)端口是7000 #?如果想要修改端口, 可以使用 -port 端口號(hào)的方式修改 jhat -port 8088 heap.bin jhat heap.bin
-
接下來我們就可以在瀏覽器中查看了 , 這里展示的內(nèi)存中的所有對(duì)象的類型
注意, 默認(rèn)顯示的是不包含jdk原生的類型的, 所以, String類型這里顯示不出來, 需要將頁(yè)面滑動(dòng)到最下面
All classes including platform: 顯示所有的類型,包含java原生的類型
Show all members of the rootset: 顯示所有的根節(jié)點(diǎn)
Show instance counts for all classes (including platform): 顯示所有的類型的實(shí)例對(duì)象數(shù)量,包含jdk原生的類型
Show instance counts for all classes (excluding platform): 顯示所有的類型的實(shí)例對(duì)象數(shù)量,不包含jdk原生的類型
Show heap histogram : 顯示堆內(nèi)存的統(tǒng)計(jì)信息, 其實(shí)這里就是上面 jmap -histo:live 命令展示的結(jié)果
Show finalizer summary: 實(shí)現(xiàn)即將被回收的對(duì)象的信息
Execute Object Query Language (OQL) query: 跳轉(zhuǎn)到oql執(zhí)行頁(yè)面, 可以讓我們使用類似于sql語句的形式查詢對(duì)象.
-
點(diǎn)擊 Show instance counts for all classes (including platform), 顯示所有類型的對(duì)象信息
這里我們看到, String類型的對(duì)象總共有128002個(gè)對(duì)象, 我們點(diǎn)擊去就可以看到具體的字符串對(duì)象信息了. 這里我們看到有許多重復(fù)的字符串信息, 大概就是問題所在
選擇其中一個(gè)對(duì)象,點(diǎn)擊進(jìn)去, 著重顯示的位置表示是當(dāng)前對(duì)象被那個(gè)對(duì)象引用著, 這里能看到, 當(dāng)前字符串被一個(gè)Object類型的數(shù)組引用著
我們可以通過這個(gè)關(guān)系, 一層層的往上找, 知道找到們熟悉的對(duì)象
我們點(diǎn)擊之后, 可以進(jìn)入到這個(gè)數(shù)組的詳情頁(yè)面, 這里有一個(gè)問題, 因?yàn)閿?shù)組中的元素特別多, 當(dāng)我們進(jìn)入到數(shù)組的詳情頁(yè)面之后, 他的引用關(guān)系是顯示在頁(yè)面的最下面的, 讓我們查看起來非常麻煩, 而且,如果數(shù)據(jù)量過多(>百萬), 很有可能回引起頁(yè)面崩潰.
所以, 這里我們可以使用oql語句直接查詢
在主頁(yè)上有進(jìn)入oql語句的輸入頁(yè)面
點(diǎn)擊查詢的結(jié)果, 進(jìn)入到ArrayList集合中, 我們終于看到了一個(gè)熟悉的類型: MyController
也就是說, 這個(gè)包含大量字符串對(duì)象的數(shù)組, 其實(shí)MyController中的ArrayList集合中的數(shù)據(jù), 至此, 我么便可以結(jié)合源碼, 進(jìn)一步查詢問題的所在了文章來源:http://www.zghlxwxcb.cn/news/detail-487219.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-487219.html
到了這里,關(guān)于Java內(nèi)存占用過高問題分析的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!