本文轉(zhuǎn)自: https://juejin.im/post/59e6c1f26fb9a0451c397a8c
十載專注成都網(wǎng)站制作,成都企業(yè)網(wǎng)站建設(shè),個(gè)人網(wǎng)站制作服務(wù),為大家分享網(wǎng)站制作知識(shí)、方案,網(wǎng)站設(shè)計(jì)流程、步驟,成功服務(wù)上千家企業(yè)。為您提供網(wǎng)站建設(shè),網(wǎng)站制作,網(wǎng)頁設(shè)計(jì)及定制高端網(wǎng)站建設(shè)服務(wù),專注于成都企業(yè)網(wǎng)站建設(shè),高端網(wǎng)頁制作,對(duì)成都攪拌罐車等多個(gè)領(lǐng)域,擁有多年的網(wǎng)站維護(hù)經(jīng)驗(yàn)。
本系列文章將整理到我在GitHub上的《Java面試指南》倉庫,更多精彩內(nèi)容請(qǐng)到我的倉庫里查看
https://github.com/h3pl/Java-Tutorial
喜歡的話麻煩點(diǎn)下Star哈
文章將同步到我的個(gè)人博客:
www.how2playlife.com
本文是微信公眾號(hào)【Java技術(shù)江湖】的《深入理解JVM虛擬機(jī)》其中一篇,本文部分內(nèi)容來源于網(wǎng)絡(luò),為了把本文主題講得清晰透徹,也整合了很多我認(rèn)為不錯(cuò)的技術(shù)博客內(nèi)容,引用其中了一些比較好的博客文章,如有侵權(quán),請(qǐng)聯(lián)系作者。
該系列博文會(huì)告訴你如何從入門到進(jìn)階,一步步地學(xué)習(xí)JVM基礎(chǔ)知識(shí),并上手進(jìn)行JVM調(diào)優(yōu)實(shí)戰(zhàn),JVM是每一個(gè)Java工程師必須要學(xué)習(xí)和理解的知識(shí)點(diǎn),你必須要掌握其實(shí)現(xiàn)原理,才能更完整地了解整個(gè)Java技術(shù)體系,形成自己的知識(shí)框架。
為了更好地總結(jié)和檢驗(yàn)?zāi)愕膶W(xué)習(xí)成果,本系列文章也會(huì)提供每個(gè)知識(shí)點(diǎn)對(duì)應(yīng)的面試題以及參考答案。
如果對(duì)本系列文章有什么建議,或者是有什么疑問的話,也可以關(guān)注公眾號(hào)【Java技術(shù)江湖】聯(lián)系作者,歡迎你參與本系列博文的創(chuàng)作和修訂。
在常見的線上問題時(shí)候,我們多數(shù)會(huì)遇到以下問題:
- 內(nèi)存泄露
- 某個(gè)進(jìn)程突然cpu飆升
- 線程死鎖
- 響應(yīng)變慢…等等其他問題。
如果遇到了以上這種問題,在線下可以有各種本地工具支持查看,但到線上了,就沒有這么多的本地調(diào)試工具支持,我們?cè)撊绾位诒O(jiān)控工具來進(jìn)行定位問題?
我們一般會(huì)基于數(shù)據(jù)收集來定位,而數(shù)據(jù)的收集離不開監(jiān)控工具的處理,比如:運(yùn)行日志、異常堆棧、GC日志、線程快照、堆快照等。經(jīng)常使用恰當(dāng)?shù)姆治龊捅O(jiān)控工具可以加快我們的分析數(shù)據(jù)、定位解決問題的速度。以下我們將會(huì)詳細(xì)介紹。
jps [options] [hostid]復(fù)制代碼
如果不指定hostid就默認(rèn)為當(dāng)前主機(jī)或服務(wù)器。
命令行參數(shù)選項(xiàng)說明如下:
-q 不輸出類名、Jar名和傳入main方法的參數(shù)
- l 輸出main類或Jar的全限名
-m 輸出傳入main方法的參數(shù)
- v 輸出傳入JVM的參數(shù)復(fù)制代碼
jstat 是用于見識(shí)虛擬機(jī)各種運(yùn)行狀態(tài)信息的命令行工具。它可以顯示本地或者遠(yuǎn)程虛擬機(jī)進(jìn)程中的類裝載、內(nèi)存、垃圾收集、jit編譯等運(yùn)行數(shù)據(jù),它是線上定位jvm性能的首選工具。
命令格式:
jstat [ generalOption | outputOptions vmid [interval[s|ms] [count]] ]
generalOption - 單個(gè)的常用的命令行選項(xiàng),如-help, -options, 或 -version。
outputOptions -一個(gè)或多個(gè)輸出選項(xiàng),由單個(gè)的statOption選項(xiàng)組成,可以和-t, -h, and -J等選項(xiàng)配合使用。復(fù)制代碼
參數(shù)選項(xiàng):
Option | Displays | Ex |
---|---|---|
class | 用于查看類加載情況的統(tǒng)計(jì) | jstat -class pid:顯示加載class的數(shù)量,及所占空間等信息。 |
compiler | 查看HotSpot中即時(shí)編譯器編譯情況的統(tǒng)計(jì) | jstat -compiler pid:顯示VM實(shí)時(shí)編譯的數(shù)量等信息。 |
gc | 查看JVM中堆的垃圾收集情況的統(tǒng)計(jì) | jstat -gc pid:可以顯示gc的信息,查看gc的次數(shù),及時(shí)間。其中最后五項(xiàng),分別是young gc的次數(shù),young gc的時(shí)間,full gc的次數(shù),full gc的時(shí)間,gc的總時(shí)間。 |
gccapacity | 查看新生代、老生代及持久代的存儲(chǔ)容量情況 | jstat -gccapacity:可以顯示,VM內(nèi)存中三代(young,old,perm)對(duì)象的使用和占用大小 |
gccause | 查看垃圾收集的統(tǒng)計(jì)情況(這個(gè)和-gcutil選項(xiàng)一樣),如果有發(fā)生垃圾收集,它還會(huì)顯示最后一次及當(dāng)前正在發(fā)生垃圾收集的原因。 | jstat -gccause:顯示gc原因 |
gcnew | 查看新生代垃圾收集的情況 | jstat -gcnew pid:new對(duì)象的信息 |
gcnewcapacity | 用于查看新生代的存儲(chǔ)容量情況 | jstat -gcnewcapacity pid:new對(duì)象的信息及其占用量 |
gcold | 用于查看老生代及持久代發(fā)生GC的情況 | jstat -gcold pid:old對(duì)象的信息 |
gcoldcapacity | 用于查看老生代的容量 | jstat -gcoldcapacity pid:old對(duì)象的信息及其占用量 |
gcpermcapacity | 用于查看持久代的容量 | jstat -gcpermcapacity pid: perm對(duì)象的信息及其占用量 |
gcutil | 查看新生代、老生代及持代垃圾收集的情況 | jstat -util pid:統(tǒng)計(jì)gc信息統(tǒng)計(jì) |
printcompilation | HotSpot編譯方法的統(tǒng)計(jì) | jstat -printcompilation pid:當(dāng)前VM執(zhí)行的信息 |
例如:
查看gc 情況執(zhí)行:jstat-gcutil 27777
命令格式:
jinfo[option] pid復(fù)制代碼
比如:獲取一些當(dāng)前進(jìn)程的jvm運(yùn)行和啟動(dòng)信息。
jmap命令用于生產(chǎn)堆轉(zhuǎn)存快照。打印出某個(gè)java進(jìn)程(使用pid)內(nèi)存內(nèi)的,所有‘對(duì)象’的情況(如:產(chǎn)生那些對(duì)象,及其數(shù)量)。
命令格式:
jmap [ option ] pid
jmap [ option ] executable core
jmap [ option ] [server-id@]remote-hostname-or-IP復(fù)制代碼
參數(shù)選項(xiàng):
-dump:[live,]format=b,file=<filename> 使用hprof二進(jìn)制形式,輸出jvm的heap內(nèi)容到文件=. live子選項(xiàng)是可選的,假如指定live選項(xiàng),那么只輸出活的對(duì)象到文件.
-finalizerinfo 打印正等候回收的對(duì)象的信息.
-heap 打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情況.
-histo[:live] 打印每個(gè)class的實(shí)例數(shù)目,內(nèi)存占用,類全名信息. VM的內(nèi)部類名字開頭會(huì)加上前綴”*”. 如果live子參數(shù)加上后,只統(tǒng)計(jì)活的對(duì)象數(shù)量.
-permstat 打印classload和jvm heap長久層的信息. 包含每個(gè)classloader的名字,活潑性,地址,父classloader和加載的class數(shù)量. 另外,內(nèi)部String的數(shù)量和占用內(nèi)存數(shù)也會(huì)打印出來.
-F 強(qiáng)迫.在pid沒有相應(yīng)的時(shí)候使用-dump或者-histo參數(shù). 在這個(gè)模式下,live子參數(shù)無效.
-h | -help 打印輔助信息
-J 傳遞參數(shù)給jmap啟動(dòng)的jvm. 復(fù)制代碼
jhat 命令與jamp搭配使用,用來分析map生產(chǎn)的堆快存儲(chǔ)快照。jhat內(nèi)置了一個(gè)微型http/Html服務(wù)器,可以在瀏覽器找那個(gè)查看。不過建議盡量不用,既然有dumpt文件,可以從生產(chǎn)環(huán)境拉取下來,然后通過本地可視化工具來分析,這樣既減輕了線上服務(wù)器壓力,有可以分析的足夠詳盡(比如 MAT/jprofile/visualVm)等。
jstack用于生成java虛擬機(jī)當(dāng)前時(shí)刻的線程快照。線程快照是當(dāng)前java虛擬機(jī)內(nèi)每一條線程正在執(zhí)行的方法堆棧的集合,生成線程快照的主要目的是定位線程出現(xiàn)長時(shí)間停頓的原因,如線程間死鎖、死循環(huán)、請(qǐng)求外部資源導(dǎo)致的長時(shí)間等待等。
命令格式:
jstack [ option ] pid
jstack [ option ] executable core
jstack [ option ] [server-id@]remote-hostname-or-IP復(fù)制代碼
參數(shù):
-F當(dāng)’jstack [-l] pid’沒有相應(yīng)的時(shí)候強(qiáng)制打印棧信息
-l長列表. 打印關(guān)于鎖的附加信息,例如屬于java.util.concurrent的ownable synchronizers列表.
-m打印java和native c/c++框架的所有棧信息.
-h | -help打印幫助信息
pid 需要被打印配置信息的java進(jìn)程id,可以用jps查詢.復(fù)制代碼
后續(xù)的查找耗費(fèi)最高cpu例子會(huì)用到。
對(duì)jvm監(jiān)控的常見可視化工具,除了jdk本身提供的Jconsole和visualVm以外,還有第三方提供的jprofilter,perfino,Yourkit,Perf4j,JProbe,MAT等。這些工具都極大的豐富了我們定位以及優(yōu)化jvm方式。
這些工具的使用,網(wǎng)上有很多教程提供,這里就不再過多介紹了。對(duì)于VisualVm來說,比較推薦使用,它除了對(duì)jvm的侵入性比較低以外,還是jdk團(tuán)隊(duì)自己開發(fā)的,相信以后功能會(huì)更加豐富和完善。jprofilter對(duì)于第三方監(jiān)控工具,提供的功能和可視化最為完善,目前多數(shù)ide都支持其插件,對(duì)于上線前的調(diào)試以及性能調(diào)優(yōu)可以配合使用。
另外對(duì)于線上dump的heap信息,應(yīng)該盡量拉去到線下用于可視化工具來分析,這樣分析更詳細(xì)。如果對(duì)于一些緊急的問題,必須需要通過線上監(jiān)控,可以采用 VisualVm的遠(yuǎn)程功能來進(jìn)行,這需要使用tool.jar下的MAT功能。
在線上有時(shí)候某個(gè)時(shí)刻,可能會(huì)出現(xiàn)應(yīng)用某個(gè)時(shí)刻突然cpu飆升的問題。對(duì)此我們應(yīng)該熟悉一些指令,快速排查對(duì)應(yīng)代碼。
1.找到最耗CPU的進(jìn)程
指令:top復(fù)制代碼
2.找到該進(jìn)程下最耗費(fèi)cpu的線程
指令:top -Hp pid復(fù)制代碼
3.轉(zhuǎn)換進(jìn)制
printf “%x\n” 15332 // 轉(zhuǎn)換16進(jìn)制(轉(zhuǎn)換后為0x3be4) 復(fù)制代碼
4.過濾指定線程,打印堆棧信息
指令:
jstack pid |grep 'threadPid' -C5 --color
jstack 13525 |grep '0x3be4' -C5 --color // 打印進(jìn)程堆棧 并通過線程id,過濾得到線程堆棧信息。復(fù)制代碼
可以看到是一個(gè)上報(bào)程序,占用過多cpu了(以上例子只為示例,本身耗費(fèi)cpu并不高)
有時(shí)候部署場景會(huì)有線程死鎖的問題發(fā)生,但又不常見。此時(shí)我們采用jstack查看下一下。比如說我們現(xiàn)在已經(jīng)有一個(gè)線程死鎖的程序,導(dǎo)致某些操作waiting中。
1.查找java進(jìn)程id
指令:top 或者 jps 復(fù)制代碼
指令:jstack -l pid復(fù)制代碼
從輸出信息可以看到,有一個(gè)線程死鎖發(fā)生,并且指出了那行代碼出現(xiàn)的。如此可以快速排查問題。
java堆內(nèi)的OOM異常是實(shí)際應(yīng)用中常見的內(nèi)存溢出異常。一般我們都是先通過內(nèi)存映射分析工具(比如MAT)對(duì)dump出來的堆轉(zhuǎn)存快照進(jìn)行分析,確認(rèn)內(nèi)存中對(duì)象是否出現(xiàn)問題。
當(dāng)然了出現(xiàn)OOM的原因有很多,并非是堆中申請(qǐng)資源不足一種情況。還有可能是申請(qǐng)?zhí)噘Y源沒有釋放,或者是頻繁頻繁申請(qǐng),系統(tǒng)資源耗盡。針對(duì)這三種情況我需要一一排查。
OOM的三種情況:
1.申請(qǐng)資源(內(nèi)存)過小,不夠用。
2.申請(qǐng)資源太多,沒有釋放。
3.申請(qǐng)資源過多,資源耗盡。比如:線程過多,線程內(nèi)存過大等。
1.排查申請(qǐng)申請(qǐng)資源問題。
指令:jmap -heap 11869 復(fù)制代碼
查看新生代,老生代堆內(nèi)存的分配大小以及使用情況,看是否本身分配過小。
從上述排查,發(fā)現(xiàn)程序申請(qǐng)的內(nèi)存沒有問題。
2.排查gc
特別是fgc情況下,各個(gè)分代內(nèi)存情況。
指令:jstat -gcutil 11938 1000 每秒輸出一次gc的分代內(nèi)存分配情況,以及gc時(shí)間復(fù)制代碼
3.查找最費(fèi)內(nèi)存的對(duì)象
指令: jmap -histo:live 11869 | more復(fù)制代碼
上述輸出信息中,最大內(nèi)存對(duì)象才161kb,屬于正常范圍。如果某個(gè)對(duì)象占用空間很大,比如超過了100Mb,應(yīng)該著重分析,為何沒有釋放。
注意,上述指令:
jmap -histo:live 11869 | more
執(zhí)行之后,會(huì)造成jvm強(qiáng)制執(zhí)行一次fgc,在線上不推薦使用,可以采取dump內(nèi)存快照,線下采用可視化工具進(jìn)行分析,更加詳盡。
jmap -dump:format=b,file=/tmp/dump.dat 11869
或者采用線上運(yùn)維工具,自動(dòng)化處理,方便快速定位,遺失出錯(cuò)時(shí)間。復(fù)制代碼
4.確認(rèn)資源是否耗盡
- pstree 查看進(jìn)程線程數(shù)量
- netstat 查看網(wǎng)絡(luò)連接數(shù)量
或者采用:
- ll /proc/${PID}/fd | wc -l // 打開的句柄數(shù)
- ll /proc/${PID}/task | wc -l (效果等同pstree -p | wc -l) //打開的線程數(shù)
以上就是一些常見的jvm命令應(yīng)用。
一種工具的應(yīng)用并非是萬能,包治百病,問題的解決往往是需要多種工具的結(jié)合才能更好的定位問題,無論使用何種分析工具,最重要的是熟悉每種工具的優(yōu)勢和劣勢。這樣才能取長補(bǔ)短,配合使用。
https://segmentfault.com/a/1190000009707894
https://www.cnblogs.com/hysum/p/7100874.html
http://c.biancheng.net/view/939.html
https://www.runoob.com/
https://blog.csdn.net/android_hl/article/details/53228348
文章題目:深入理解JVM虛擬機(jī)9:JVM監(jiān)控工具與診斷實(shí)踐
瀏覽路徑:http://m.newbst.com/article0/jhssio.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供小程序開發(fā)、外貿(mào)建站、商城網(wǎng)站、App開發(fā)、移動(dòng)網(wǎng)站建設(shè)、虛擬主機(jī)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)