JVM学习笔记之-JVM性能监控-JVM监控及诊断工具-GUI方式-Visual VM-JProfiler-Arthas
00-談GUI工具前的補充
補充1:內存泄漏
內存泄漏的理解與分類
何為內存泄漏( memory leak)
可達性分析算法來判斷對象是否是不再使用的對象,本質都是判斷一個對象是否還被引用。那么對于這種情況下,由于代碼的實現不同就會出現很多種內存泄漏問題(讓JVM誤以為此對象還在引用中,無法回收,造成內存泄漏)。
內存泄漏( memory leak)的理解
嚴格來說,只有對象不會再被程序用到了,但是GC又不能回收他們的情況,才叫內存泄漏。
但實際情況很多時候一些不太好的實踐(或疏忽)會導致對象的生命周期變得很長甚至導致OOM,也可以叫做寬泛意義上的“內存泄漏”。
對象X引用對象Y,X的生命周期比Y的生命周期長;
那么當Y生命周期結束的時候,X依然引用著Y,這時候,垃圾回收期是不會回收對象Y的;
如果對象x還引用著生命周期比較短的A、B、C,對象A又引用著對象 a、b、c,這樣就可能造成大量無用的對象不能被回收,進而占據了內存資源,造成內存泄漏,直到內存溢出。
內存泄漏與內存溢出的關系:
1.內存泄漏(memory leak )
申請了內存用完了不釋放,比如一共有1024M 的內存,分配了512M 的內存一直不回收,那么可以用的內存只有512M 了,仿佛泄露掉了一部分;
通俗一點講的話,內存泄漏就是【占著茅坑不拉shi】。
2.內存溢出(out of memory)
申請內存時,沒有足夠的內存可以使用;
通俗一點兒講,一個廁所就三個坑,有兩個站著茅坑不走的(內存泄漏),剩下最后一個坑,廁所表示接待壓力很大,這時候一下子來了兩個人,坑位(內存)就不夠了,內存泄漏變成內存溢出了。
可見,內存泄漏和內存溢出的關系: 內存泄漏的增多,最終會導致內存溢出。
泄漏的分類
經常發生:發生內存泄露的代碼會被多次執行,每次執行,泄露一塊內存;
偶然發生:在某些特定情況下才會發生;
一次性:發生內存泄露的方法只會執行一次;
隱式泄漏:一直占著內存不釋放,直到執行結束;嚴格的說這個不算內存泄漏,因為最終釋放掉了,但是如果執行時間特別長,也可能會導致內存耗盡。
Java中內存泄漏的8種情況
1-靜態集合類
靜態集合類,如HashMap、LinkedList等等。如果這些容器為靜態的,那么它們的生命周期與JVM程序一致,則容器中的對象在程序結束之前將不能被釋放,從而造成內存泄漏。簡單而言,長生命周期的對象持有短生命周期對象的引用,盡管短生命周期的對象不再使用,但是因為長生命周期對象持有它的引用而導致不能被回收。
2-單例模式
單例模式,和靜態集合導致內存泄露的原因類似,因為單例的靜態特性,它的生命周期和JVM 的生命周期一樣長,所以如果單例對象如果持有外部對象的引用,那么這個外部對象也不會被回收,那么就會造成內存泄漏。
3-內部類持有外部類
內部類持有外部類,如果一個外部類的實例對象的方法返回了一個內部類的實例對象。
這個內部類對象被長期引用了,即使那個外部類實例對象不再被使用,但由于內部類持有外部類的實例對象,這個外部類對象將不會被垃圾回收,這也會造成內存泄漏。
4-各種連接,如數據庫連接、網絡連接和IO連接等
各種連接,如數據庫連接、網絡連接和IO連接等。
在對數據庫進行操作的過程中,首先需要建立與數據庫的連接,當不再使用時,需要調用close方法來釋放與數據庫的連接。只有連接被關閉后,垃圾回收器才會回收對應的對象。
否則,如果在訪問數據庫的過程中,對Connection、Statement或ResultSet不顯性地關閉,將會造成大量的對象無法被回收,從而引起內存泄漏。
5-變量不合理的作用域
變量不合理的作用域。一般而言,一個變量的定義的作用范圍大于其使用范圍,很有可能會造成內存泄漏。另一方面,如果沒有及時地把對象設置為null,很有可能導致內存泄漏的發生。
如下面的偽代碼
如上面這個偽代碼,通過readFronNet方法把接受的消息保存在變量msg中,然后調用saveDB方法把msg的內容保存到數據庫中,此時msg已經就沒用了,由于msg的生命周期與對象的生命周期相同,此時msg還不能回收,因此造成了內存泄漏。
實際上這個msg變量可以放在receiveMsg方法內部,當方法使用完,那么msg的生命周期也就結束,此時就可以回收了。還有一種方法,在使用完msg后,把msg設置為null,這樣垃圾回收器也會回收msg的內存空間。
6-改變哈希值
改變哈希值,當一個對象被存儲進HashSet集合中以后,就不能修改這個對象中的那些參與計算哈希值的字段了。
否則,對象修改后的哈希值與最初存儲進HashSet集合中時的哈希值就不同了,在這種情況下,即使在contains方法使用該對象的當前引用作為的參數去HashSet集合中檢索對象,也將返回找不到對象的結果,這也會導致無法從HashSet集合中單獨刪除當前對象,造成內存泄漏。
這也是 string為什么被設置成了不可變類型,我們可以放心地把 String存入 HashSet,或者把String當做HashMap 的key值;
當我們想把自己定義的類保存到散列表的時候,需要保證對象的 hashCode 不可變。
7-緩存泄漏
內存泄漏的另一個常見來源是緩存,一旦你把對象引用放入到緩存中,他就很容易遺忘。比如:之前項目在一次上線的時候,應用啟動奇慢直到夯死,就是因為代碼中會加載一個表中的數據到緩存(內存)中,測試環境只有幾百條數據,但是生產環境有幾百萬的數據。
對于這個問題,可以使用WeakHashMap代表緩存,此種Map的特點是,當除了自身有對key的引用外,此key沒有其他引用那么此map會自動丟棄此值。
8-監聽器和回調
內存泄漏第三個常見來源是監聽器和其他回調,如果客戶端在你實現的API中注冊回調,卻沒有顯示的取消,那么就會積聚。
需要確保回調立即被當作垃圾回收的最佳方法是只保存它的弱引用,例如將他們保存成為WeakHashMap中的鍵。
補充2:支持使用OQL語言查詢對象信息
MAT支持一種類似于SQL的查詢語言OQL(Object Query Language)。OQL使用類SQL語法,可以在堆中進行對象的查找和篩選。
SELECT子句
在NAT中,Select子句的格式與SQL基本一致,用于指定要顯示的列。Select子句中可以使用“*”,查看結果對象的引用實例(相當于outgoing references)。
SELECT * FROM java.util.Vector v
使用“OBECTS”關鍵字,可以將返回結果集中的項以對象的形式顯示。
SELECT objects v.elementData FROM java.util.Vector v
SELECT OBECTS s.value FROM java.lang.String s
在Select子句中,使用“AS RETAINED SET”關鍵字可以得到所得對象的保留集。
SELECT AS RETAINED SET *FROM com.fs.mat. Student
“DISTINCT”關鍵字用于在結果集中去除重復對象。
SELECT DISTINCT OBJECTS classof(s)FROM java.lang.String s
FROM子句
From子句用于指定查詢范圍,它可以指定類名、正則表達式或者對象地址。
SELECT *FROM java. lang.String s
下例使用正則表達式,限定搜索范圍,輸出所有com.fs包下所有類的實例
SELECT *FROM “com\ .fs…*”
也可以直接使用類的地址進行搜索。使用類的地址的好處是可以區分被不同ClassLoader加載的同一種類型。
select* from 0x37a0b4d
WHERE子句
Where子句用于指定0QL的查詢條件。0QL查詢將只返回滿足where子句指定條件的對象。Where子句的格式與傳統SQL極為相似。
下例返回長度大于10的char數組。
SELECT* FROM char[] s WHERE s.@length>10
下例返回包含“java”子字符串的所有字符串,使用“LIKE”操作符,“LIKE”操作符的操作參數為正則表達式。
SELECT * FROM java.lang.String s WHERE toString(s)LIKE “.*java.*”
下例返回所有value域不為null的字符串,使用“=”操作符。
SELECT * FROM java.lang.String s where s.value!=null
Where子句支持多個條件的AND、OR運算。下例返回數組長度大于15,并且深堆大于1000字節的所有Vector對象。
SELECT * FROM java.util.Vector v WHERE v.elementData.@length>15 AND v.@retainedHeapsize>1000
內置對象與方法
0QL中可以訪問堆內對象的屬性,也可以訪問堆內代理對象的屬性。訪問堆內對象的屬性時,格式如下:
[ <alias>. ] <field> . <field>. <field>其中alias為對象名稱。
訪問java.io.File對象的path屬性,并進一步訪問path的value屬性:
SELECT toString(f.path.value) FROM java.io.File f
下例顯示了String對象的內容、objectid和objectAddress。
SELECT s.toString(),s.@objectId,s.@objectAddress FROMjava.lang.String s
下例顯示java.util.Vector內部數組的長度。
SELECT v.elementData.@length FROM java.util.Vector v
下例顯示了所有的java.util.Vector對象及其子類型
select *from INSTANCEOF java.util.Vector
01-工具概述
使用命令行工具或組合能幫您獲取目標Java應用性能相關的基礎信息,但它們存在下列局限:
1.無法獲取方法級別的分析數據,如方法間的調用關系、各方法的調用次數和調用時間等(這對定位應用性能瓶頸至關重要)。
2.要求用戶登錄到目標Java應用所在的宿主機上,使用起來不是很方便。3.分析數據通過終端輸出,結果展示不夠直觀。
為此,JDK提供了一些內存泄漏的分析工具,如jconsole,jvisualvm等,用于輔助開發人員定位問題,但是這些工具很多時候并不足以滿足快速定位的需求。所以這里我們介紹的工具相對多一些、豐富一些。
圖形化綜合診斷工具
JDK自帶的工具
jconsole
jconsole:JDK自帶的可視化監控工具。查看Java應用程序的運行概況、監控堆信
息、永久區(或元空間)使用情況、類加載情況等
—>位置:jdk \bin\jconsole.exe
Visual VM
Visual VM是一個工具,它提供了一個可視界面,用于查看Java虛擬機上運行的基于Java技術的應用程序的詳細信息。
—>位置:jdk\binljvisualvm.exe
JMC:Java Mission Control
JMC:Java Mission Control,內置Java Flight Recorder。能夠以極低的性能開銷收集Java虛擬機的性能數據。
第三方工具
MAT:MAT(Memory Analyzer Tool)
MAT:MAT(Memory Analyzer Tool)是基于Eclipse的內存分析工具,是一個快
速、功能豐富的Java heap分析工具,它可以幫助我們查找內存泄漏和減少內存消耗
—>Eclipse的插件形式
JProfiler
JProfiler:商業軟件,需要付費。功能強大。
—>與VisualVM類似 I
Arthas
Arthas:Alibaba開源的Java診斷工具。深受開發者喜愛。
Btrace
Btrace:Java運行時追蹤工具。可以在不停機的情況下,跟蹤指定的方法調用、構
造函數調用和系統內存等信息。
02-jConsole 了解
基本概述
從Java5開始,在JDK中自帶的java監控和管理控制臺。
用于對JVM中內存、線程和類等的監控,是一個基于JMX(java management extensions)的GUI性能監控工具。
官方教程:
https://docs.oracle.com/javase/7/docs/technotes/guides/management/jconsole.htm1
啟動
cmd命令啟動(需要配置環境變量)
三種連接方式
Local
使用JConsole連接一個正在本地系統運行的JVM,并且執行程序的和運行JConsole的需要
是同一個用戶。JConsole使用文件系統的授權通過RMI連接器連接到平臺的MBean服務器上。
這種從本地連接的監控能力只有Sun的JDK具有。
Remote
使用下面的URL通過RMI連接器連接到一個JMX代理,servicejm.rmi://jindi/rmi:/hostName:portNum/jimkrmi。
JConsole為建立連接,需要在環境變量中設置mx.remote.credentials來指定用戶名和密碼,從而進行授權。
Advanced
使用一個特殊的URL連接JMX代理。一般情況使用自己定制的連接器而不是RMI提供的連接器
來連接JMX代理,或者是一個使用JDK1.4的實現了JMX和JMX Rmote的應用。
03-Visual VM 重要
基本概述
Visual VM是一個功能強大的多合一故障診斷和性能監控的可視化工具。
它集成了多個JDK命令行工具,使用visual VM可用于顯示虛擬機進程及進程的配置和環境信息(jps,jinfo),監視應用程序的CPU、GC、堆、方法區及線程的信息(jstat、jstack)等,甚至代替JConsole。
在JDK 6 Update 7以后,Visual VM便作為JDK的一部分發布(VisualVM在JDK/bin目錄下),即:它完全免費。
此外,Visual VM也可以作為獨立的軟件安裝:
首頁: https: //visualvm.github.io/index.html
插件的安裝
Visual VM的一大特點是支持插件擴展,并且插件安裝非常方便。我們既可以通過離線下載插件文件*.nbm,然后在Plugin對話框的已下載頁面下,添加已下載的插件。也可以在可用插件頁面下,在線安裝插件。(這里建議安裝上:VisualGC)
插件地址: https://visualvm.github.io/pluginscenters.html
安裝VisualGC插件
連接方式
本地連接
監控本地Java進程的CPU、類、線程等
遠程連接
1-確定遠程服務器的ip地址
2-添加JMX(通過JMX技術具體監控遠端服務器哪個Java進程
3-修改bin/catalina.sh文件,連接遠程的tomcat
4-在…/conf中添加jmxremote.access和jmxremote.password文件
5-將服務器地址改為公網ip地址
6-設置阿里云安全策略和防火墻策略
7-啟動tomcat,查看tomcat啟動日志和端口監聽
8-JMX中輸入端口號、用戶名、密碼登錄
主要功能
1-生成/讀取堆內存快照
查看其他dump文件
2-查看JVM參數和系統屬性
3-查看運行中的虛擬機進程
4-生成/讀取線程快照
5.程序資源的實時監控
6.其他功能
遠程環境監控
CPU分析和內存分析
JMX代理連接
04-eclipse MAT
MAT(Memory Analyzer Tool)工具是一款功能強大的Java堆內存分析器。可以用于查找內存泄漏以及查看內存消耗情況。
MAT是基于Eclipse開發的,不僅可以單獨使用,還可以作為插件的形式嵌入在Eclipse中使用。是一款免費的性能分析工具,使用起來非常方便。大家可以在
https://www.eclipse.org/mat/downloads.php下載并使用MAT。
運行獨立版本的內存分析器所需的最低 Java 版本是 Java 11。請參閱JRE/JDK 來源。
本次不做此工具的詳解
05-JProfiler 重要
基本概述
介紹
在運行Java的時候有時候想測試運行時占用內存情況,這時候就需要使用測試工具查看了。在
eclipse里面有 Eclipse Memory Analyzer tool(MAT)插件可以測試,而在IDEA中也有這么一個插件,就是JProfiler。
JProfiler是由 ej-technologies 公司開發的一款 Java應用性能診斷工具。功能強大,但是收費。
官網下載地址: https : //www.ej-technologies.com/products/jprofiler/overview.html
特點
特點:
·使用方便、界面操作友好(簡單且強大)
·對被分析的應用影響小(提供模板)
. CPU, Thread ,Memory分析功能尤其強大
·支持對jdbc , noSql,jsp, servlet, socket等進行分析
·支持多種模式(離線,在線)的分析
·支持監控本地、遠程的VM
·跨平臺,擁有多種操作系統的安裝版本
主要功能
1-方法調用
對方法調用的分析可以幫助您了解應用程序正在做什么,并找到提高其性能的方法
2-內存分配
通過分析堆上對象、引用鏈和垃圾收集能幫您修復內存泄漏問題,優化內存使用
3-線程和鎖
JProfiler提供多種針對線程和鎖的分析視圖助您發現多線程問題
4-高級子系統
許多性能問題都發生在更高的語義級別上。例如,對于JDBC調用,您可能希望找出
執行最慢的SQL語句。JProfiler支持對這些子系統進行集成分析
安裝與配置
下載與安裝
官網下載地址: https : //www.ej-technologies.com/products/jprofiler/overview.html
官方下載安裝就是
JProfiler中配置IDEA
IDEA集成JProfiler
點擊idea上面的JProfiler圖標即可啟動當前程序
具體使用
數據采集方式
JProfier數據采集方式分為兩種:Sampling(樣本采集)和Instrumentation(重構模式)
注:JProfiler本身沒有指出數據的采集類型,這里的采集類型是針對方法調用的采集類型。因為Profiler的絕大多數核心功能都依賴方法調用采集的數據,所以可以直接認為是Profiler的數據采集類型。
lnstrumentation重構模式
.Instrumentation:這是JProfiler全功能模式。在class加載之前,JProfier把相關功能代碼寫入到需要分析的class的bytecode中,對正在運行的jvm有一定影響。
優點:功能強大。在此設置中,調用堆棧信息是準確的。
缺點:若要分析的class較多,則對應用的性能影響較大,CPU開銷可能很高(取決于Filter的控制)。因此使用此模式一般配合Filter使用,只對特定的類或包進行分析
Sampling抽樣模式(一般推薦使用此方式)
.Sampling:類似于樣本統計,每隔一定時間(5ms)將每個線程棧中方法棧中的信息統計出來
優點:對CPU的開銷非常低,對應用影響小(即使你不配置任何Filter)
缺點:一些數據/特性不能提供(例如:方法的調用次數、執行時間)
遙感監測Telemetries
內存視圖Live Memory
Live memory 內存剖析: class/class instance的相關信息。例如對象的個數,大小,對象創建的方法執行棧,對象創建的熱點。
所有對象A11 0bjects
顯示所有加載的類的列表和在堆上分配的實例數。只有Java 1.5(JVMTI)才會顯示此視圖。
記錄對象 Record objects
查看特定時間段對象的分配,并記錄分配的調用堆棧。
分配訪問樹Allocation Call Tree
顯示一棵請求樹或者方法、類、包或對已選擇類有帶注釋的分配信息的J2EE組件。
分配熱點 Allocation Hot Spots
顯示一個列表,包括方法、類、包或分配已選類的72EE組件。你可以標注當前值并且顯示差異值。對于每個熱點都可以顯示它的跟蹤記錄樹。
類追蹤器class Tracker
類跟蹤視圖可以包含任意數量的圖表,顯示選定的類和包的實例與時間。
堆遍歷heap walker
cpu視圖cpu views
線程視圖threads
Profiler通過對線程歷史的監控判斷其運行狀態,并監控是否有線程阻塞產生,還能將一個線程所管理的方法以樹狀形式呈現。對線程剖析。
線程分析主要關心三個方面:
線程歷史Thread History
顯示一個與線程活動和線程狀態在一起的活動時間表。
線程監控Thread Monitor
顯示一個列表,包括所有的活動線程以及它們目前的活動狀況。
線程轉儲 Thread Dumps
顯示所有線程的堆棧跟蹤。
監視器&鎖Monitors&locks
監控和鎖Monitors & Locks所有線程持有鎖的情況以及鎖的信息。觀察VM的內部線程并查看狀態:
死鎖探測圖表Current Locking Graph :顯示JVM中的當前死鎖圖表。
目前使用的監測器 Current Monitors :顯示目前使用的監測器并且包括它們的關聯線程。
鎖定歷史圖表Locking History Graph :顯示記錄在VM中的鎖定歷史。
歷史檢測記錄 Monitor History :顯示重大的等待事件和阻塞事件的歷史記錄。
監控器使用統計 Monitor Usage Statistics :顯示分組監測,線程和監測類的統計監測數據
06-Arthas 阿里巴巴 建議查閱官方文檔
基本概述
概述
Arthas(阿爾薩斯)是Alibaba開源的Java診斷工具,深受開發者喜愛。在線排查問題,無需重啟;動態跟蹤Java代碼;實時監控JVM狀態。
Arthas支持JDK 6+,支持Linux/Mac/Windows,采用命令行交互模式,同時提供豐富的Tab自動補全功能,進一步方便進行問題的定位和診斷。
官方使用文檔
https://arthas.aliyun.com/doc/index.html
安裝與使用
下載arthas
直接使用此鏈接https://arthas.aliyun.com/arthas-boot.jar下載
Arthas Spring Boot Starter
https://arthas.aliyun.com/doc/spring-boot-starter.html
配置maven依賴:
<dependency><groupId>com.taobao.arthas</groupId><artifactId>arthas-spring-boot-starter</artifactId><version>${arthas.version}</version></dependency>09-Flame Graphs(火焰圖)
在追求極致性能的場景下,了解你的程序運行過程中cpu在干什么很重要,火焰圖就是一種非常直觀的展示cpu在程序整個生命周期過程中時間分配的工具。
火焰圖對于現代的程序員不應該陌生,這個工具可以非常直觀的顯示出調用棧中的CPU消耗瓶頸。
網上的關于java火焰圖的講解大部分來自于Brendan Gregg的博客:
http://www.brendangregg.com/flamegraphs.html
總結
以上是生活随笔為你收集整理的JVM学习笔记之-JVM性能监控-JVM监控及诊断工具-GUI方式-Visual VM-JProfiler-Arthas的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JVM学习笔记之-JVM性能监控-JVM
- 下一篇: Apache-Guacamole win