歡迎關(guān)注公眾號(hào)OpenCoder麻裳,來和我做朋友吧~??????
經(jīng)過前面對(duì)于虛擬機(jī)內(nèi)存分配與回收技術(shù)各方面的介紹, 相信大家已經(jīng)建立了一個(gè)比較系統(tǒng)、 完整的理論基礎(chǔ)银择。理論總是作為指導(dǎo)實(shí)踐的工具, 把這些知識(shí)應(yīng)用到實(shí)際工作中才是我們的最終目的累舷。接下來的內(nèi)容浩考, 我們將從實(shí)踐的角度去認(rèn)識(shí)虛擬機(jī)內(nèi)存管理的世界。
給一個(gè)系統(tǒng)定位問題的時(shí)候被盈, 知識(shí)析孽、 經(jīng)驗(yàn)是關(guān)鍵基礎(chǔ), 數(shù)據(jù)是依據(jù)只怎, 工具是運(yùn)用知識(shí)處理數(shù)據(jù)的手段袜瞬。這里說的數(shù)據(jù)包括但不限于異常堆棧、 虛擬機(jī)運(yùn)行日志身堡、 垃圾收集器日志邓尤、 線程快照(threaddump/javacore文件) 、 堆轉(zhuǎn)儲(chǔ)快照(heapdump/hprof文件) 等贴谎。恰當(dāng)?shù)厥褂锰摂M機(jī)故障處理汞扎、分析的工具可以提升我們分析數(shù)據(jù)、 定位并解決問題的效率擅这, 但我們?cè)趯W(xué)習(xí)工具前澈魄, 也應(yīng)當(dāng)意識(shí)到工具永遠(yuǎn)都是知識(shí)技能的一層包裝, 沒有什么工具是“秘密武器”仲翎, 擁有了就能“包治百病”痹扇。
jps:虛擬機(jī)進(jìn)程狀況工具
jps全稱:JVM Process Status Tool ,可以列出正在運(yùn)行的虛擬機(jī)進(jìn)程谭确, 并顯示虛擬機(jī)執(zhí)行主類( Main Class帘营, main()函數(shù)所在的類)名稱以及這些進(jìn)程的本地虛擬機(jī)唯一ID( LVMID, Local Virtual Machine Identifier)
雖然功能比較單一逐哈, 但它絕對(duì)是使用頻率最高的JDK命令行工具芬迄, 因?yàn)槠渌腏DK工具大多需要輸入它查詢到的LVMID來確定要監(jiān)控的是哪一個(gè)虛擬機(jī)進(jìn)程。對(duì)于本地虛擬機(jī)進(jìn)程來說昂秃, LVMID與操作系統(tǒng)的進(jìn)程ID( PID禀梳, Process Identifier) 是一致的, 使用Windows的任務(wù)管理器或者UNIX的ps命令也可以查詢到虛擬機(jī)進(jìn)程的LVMID肠骆, 但如果同時(shí)啟動(dòng)了多個(gè)虛擬機(jī)進(jìn)程算途, 無法根據(jù)進(jìn)程名稱定位時(shí), 那就必須依賴jps命令顯示主類的功能才能區(qū)分了蚀腿。
JPS命令格式:
jps [option] [hostid]
option參數(shù)有如下:
我們常用的就是 -l 快速顯示出我們想要查看的系統(tǒng)運(yùn)行進(jìn)程所在的id嘴瓤,后續(xù)配合我們的jstat工具使用
比如我們有如下代碼:
package demo6;
public class JPSDemo {
public static void main(String[] args) throws InterruptedException {
Thread.sleep(30000);
System.out.println("hello jps");
}
}
當(dāng)我運(yùn)行起來后扫外,就可以通過IDEA 下方的Terminal工具輸入jps命令進(jìn)行查看:
我們可以看到我們當(dāng)前代碼所在的進(jìn)程ID就是15020
jstat:虛擬機(jī)統(tǒng)計(jì)信息監(jiān)視工具
jstat( JVM Statistics Monitoring Tool) 是用于監(jiān)視虛擬機(jī)各種運(yùn)行狀態(tài)信息的命令行工具。它可以顯示本地或者遠(yuǎn)程虛擬機(jī)進(jìn)程中的類加載廓脆、 內(nèi)存筛谚、 垃圾收集、 即時(shí)編譯等運(yùn)行時(shí)數(shù)據(jù)停忿, 在沒有GUI圖形界面驾讲、 只提供了純文本控制臺(tái)環(huán)境的服務(wù)器上, 它將是運(yùn)行期定位虛擬機(jī)性能問題的常用工具席赂。
jstat命令格式為:
jstat [ option vmid [interval[s|ms] [count]] ]
對(duì)于命令格式中的VMID與LVMID需要特別說明一下:如果是本地虛擬機(jī)進(jìn)程吮铭, VMID與LVMID是一致的;如果是遠(yuǎn)程虛擬機(jī)進(jìn)程颅停, 那VMID的格式應(yīng)當(dāng)是:[protocol:][//]lvmid[@hostname[:port]/servername] 參數(shù)interval和count代表查詢間隔和次數(shù)谓晌, 如果省略這2個(gè)參數(shù), 說明只查詢一次便监。假設(shè)需要每250毫秒查詢一次進(jìn)程2764垃圾收集狀況扎谎, 一共查詢20次, 那命令應(yīng)當(dāng)是:jstat -gc 2764 250 20 選項(xiàng)option代表用戶希望查詢的虛擬機(jī)信息烧董, 主要分為三類:類加載毁靶、 垃圾收集、 運(yùn)行期編譯狀況逊移。
這里知道了jstat的一些參數(shù)選項(xiàng)以及作用后预吆,我們就可以結(jié)合jps命令先查詢到我們當(dāng)前系統(tǒng)運(yùn)行的進(jìn)程ID,然后結(jié)合jstat命令來查看當(dāng)前系統(tǒng)的內(nèi)存情況胳泉,如下:
查詢結(jié)果表明:這臺(tái)服務(wù)器的新生代Eden區(qū)(E拐叉, 表示Eden) 使用了24.34%的空間, 2個(gè)Survivor區(qū)(S0扇商、 S1凤瘦, 表示Survivor0、 Survivor1) 里面都是空的案铺, 老年代(O蔬芥, 表示Old) 和 元空間 (M,表示Metaspace) 則分別使用了0%和17.34%的空間控汉。
程序運(yùn)行以來共發(fā)生Minor GC(YGC笔诵, 表示Young GC) 0次, 總耗時(shí)0.000秒姑子;發(fā)生Full GC(FGC乎婿, 表示Full GC) 0次, 總耗時(shí)(FGCT街佑, 表示Full GC Time) 為0 秒谢翎;所有GC總耗時(shí)(GCT捍靠, 表示GC Time) 為0秒。
當(dāng)然我們的代碼里面并沒有導(dǎo)致GC的發(fā)生岳服,不過jstat工具卻是能非常清晰的幫助我們看到內(nèi)存的占用情況以及所用的時(shí)間和發(fā)生的次數(shù)
我們?cè)賮砜闯S玫膅c選項(xiàng)得到的結(jié)果:
跟我們的 選項(xiàng) gcutil有些區(qū)別剂公,這里做一下解釋:
- S0C:這是s0區(qū)的大小希俩,上圖代表我們的s0區(qū)是5M大小
- S1C:這是s1區(qū)的大小吊宋,上圖代表我們的s1區(qū)是5M大小,跟S0是匹配的
- S0U/S1U:代表的是兩個(gè)Survivor區(qū)當(dāng)前使用的內(nèi)存大小颜武,目前都是0未有對(duì)象占用
- EC:Eden區(qū)的大小璃搜,32.5M
- EU:Eden區(qū)當(dāng)前使用的內(nèi)存大小,差不多8M
- OC:老年代大小鳞上,差不多85.5M
- OU:老年代當(dāng)前使用的內(nèi)存大小这吻,0代表沒有對(duì)象占用
- MC:這是方法區(qū)(永久代、元數(shù)據(jù)區(qū))的大小
- MU:這是方法區(qū)(永久代篙议、元數(shù)據(jù)區(qū))當(dāng)前使用的內(nèi)存大小
jmap和jhat:
jmap( Memory Map for Java) 命令用于生成堆轉(zhuǎn)儲(chǔ)快照( 一般稱為heapdump或dump文件)
jmap的作用并不僅僅是為了獲取堆轉(zhuǎn)儲(chǔ)快照唾糯, 它還可以查詢finalize執(zhí)行隊(duì)列、 Java堆和方法區(qū)的詳細(xì)信息鬼贱, 如空間使用率移怯、 當(dāng)前用的是哪種收集器等
jmap命令格式:
jmap [ option ] vmid
option選項(xiàng)的合法值與具體含義如下所示 :
這里使用較多的主要就是兩個(gè)Option:
- -histo :如果只是想簡(jiǎn)單了解下當(dāng)前jvm中的對(duì)象對(duì)內(nèi)存占用的情況,直接使用jmap -histo命令即可
-dump
通過命令:jmap -dump:live,format=b,file=dump.hprof PID 會(huì)在當(dāng)前目錄下生成一個(gè) dump.hrpof 文件这难,一個(gè)二進(jìn)制格式不能直接打卡舟误,需要借助jhat工具
JDK提供 jhat( JVM Heap Analysis Tool) 命令與jmap搭配使用, 來分析jmap生成的堆轉(zhuǎn)儲(chǔ)快照姻乓。
jhat內(nèi)置了一個(gè)微型的HTTP/Web服務(wù)器嵌溢, 生成堆轉(zhuǎn)儲(chǔ)快照的分析結(jié)果后, 可以在瀏覽器中查看蹋岩。不過實(shí)事求是地說赖草, 在實(shí)際工作中, 除非手上真的沒有別的工具可用剪个, 否則多數(shù)人是不會(huì)直接使用jhat命令來分析堆轉(zhuǎn)儲(chǔ)快照文件的秧骑, 主要原因有兩個(gè)方面。
一是一般不會(huì)在部署應(yīng)用程序的服務(wù)器上直接分析堆轉(zhuǎn)儲(chǔ)快照禁偎, 即使可以這樣做腿堤, 也會(huì)盡量將堆轉(zhuǎn)儲(chǔ)快照文件復(fù)制到其他機(jī)器上進(jìn)行分析, 因?yàn)榉治龉ぷ魇且粋€(gè)耗時(shí)而且極為耗費(fèi)硬件資源的過程如暖, 既然都要在其他機(jī)器上進(jìn)行笆檀, 就沒有必要再受命令行工具的限制了。
另外一個(gè)原因是jhat的分析功能相對(duì)來說比較簡(jiǎn)陋盒至, 后文將會(huì)介紹到的VisualVM酗洒, 以及專業(yè)用于分析堆轉(zhuǎn)儲(chǔ)快照文件的Eclipse Memory Analyzer士修、 IBM HeapAnalyzer等工具, 都能實(shí)現(xiàn)比jhat更強(qiáng)大專業(yè)的分析功能樱衷。
但是對(duì)于一些小公司而言棋嘲,壓力不大的情況下,我們平時(shí)可以直接通過jstat jmap jhat 等工具去看看線上系統(tǒng)的JVM運(yùn)行是否正常矩桂,有沒有頻繁Full GC的問題沸移。如果有就優(yōu)化,沒有的話侄榴,平時(shí)每天定時(shí)去看看雹锣,或者每周都去看看即可。
通過命令解析dump快照:
通過瀏覽器打開查看:
小結(jié):
本篇通過介紹JPS癞蚕、Jstat蕊爵、Jmap、Jhat工具的使用桦山,如何來進(jìn)行JVM內(nèi)存的分析攒射,大家可以自己結(jié)合一個(gè)程序進(jìn)行練習(xí)掌握工具的基本使用。后續(xù)我們將通過兩個(gè)實(shí)戰(zhàn)案例結(jié)合工具來演示如何分析調(diào)優(yōu)恒水,幫助大家進(jìn)一步掌握實(shí)操能力会放。