Java效能監控工具:VisualVM

weixin_33896726發表於2017-07-15

VisualVM是JDK自帶的一款全能型效能監控和故障分析工具,包括對CPU使用、JVM堆記憶體消耗、執行緒、類載入的實時監控,記憶體dump檔案分析,垃圾回收執行情況的視覺化分析等,對故障排查和效能調優很有幫助。在windows中安裝JDK後,VisualVM位於%JAVA_HOME%/bin/下,直接執行jvisualvm.exe即可。

VisualVM連線遠端伺服器有兩種方式:JMX和jstatd,兩種方式都不能完美支援所有功能,例如JMX不支援VisualGC,jstatd不支援CPU監控,實際使用可同時配置上並按需選用。

雙擊啟動 Java VisualVM 後可以看到視窗左側 "應用程式 "欄中有" 本地 "、"遠端 " 、"快照 "三個專案。

 "本地 "下顯示的是在 localhost 執行的 Java 程式的資源佔用情況,如果本地有 Java 程式在執行的話啟動 Java VisualVM 即可看到相應的程式名,點選程式名開啟相應的資源監控選單,以圖形的形式列出程式所佔用的 CPU 、 Heap 、 PermGen 、類、執行緒的 統計資訊。

"遠端" 項下列出的遠端主機上的 Java 程式的資源佔用情況,但需要在遠端主機上執行 jstatd 守護程式

VisualVM分為 3 類, 本地 它會自動偵測到,並顯示出來.

現在啟動IDEA.

雙擊Local 下的任一節點,看到右邊的變化 ,你可以監控 CPU ,記憶體,類,執行緒等執行狀況,實時監控伺服器效能。

 

 右鍵 VisualVM我們可以看到 Thread Dump, Heap Dump

 做 Thread Dump 很快,馬上就可以看到結果

 

 

 Heap Dump要稍花費一些時間(可以看到當前 heap 裡物件的數量及佔用的比例,做 OOM 很好用)

 

二.使用visualvm 遠端監控 JVM  

 1. 在伺服器上安裝 jstatd 元件

jstatd工具是一個RMI伺服器應用程式,主要用於監控HotSpot Java 虛擬機器的建立與終止,並提供一個介面以允許遠端監控工具附加到本地主機上執行的JVM上。

使用apt-get 命令安裝 openjdk 即可 :

sudo apt-get install openjdk-6-jdk  

2.在伺服器上配置 jstatd 的 security policy 檔案

jstatd是一個監控 JVM 從建立到銷燬過程中資源佔用情況並提供遠端監控介面的 RMI ( Remote Method Invocation ,遠端方法呼叫)伺服器程式,它是一個 Daemon 程式,要保證遠端監控軟體連線到本地的話需要 jstatd 始終保持執行。 

jstatd執行需要通過 -J-Djava.security.policy=*** 指定安全策略,因此我們需要在伺服器上建立一個指定安全策略的檔案jstatd.all.policy ,檔案內容如下:

grant codebase "file:${java.home}/../lib/tools.jar" {
   permission java.security.AllPermission;
};

3. 修改伺服器 hosts 檔案中的 IP 地址

要使Java VisualVM 成功連線到遠端伺服器上,伺服器端應該在 /etc/hosts 檔案中把本機地址設為本機的 IP 地址。使用 hostname -i 命令檢視,如果顯示的是 127.0.0.1 或者與本機實際 IP 不一致的話,需要把 /etc/hosts 檔案中相應的地址改為本機實際 IP 。

4.執行 jstatd 守護程式

 jstatd 需要保持一直執行,執行 jstatd 程式,命令如下:

jstatd -J-Djava.security.policy=jstatd.all.policy

5.通過Java VisualVM 連線到伺服器監控 Java 程式

在Java VisualVM 程式視窗左側 " 遠端 " 專案右鍵選擇 " 新增遠端主機 " ,在彈出的對話方塊中輸入遠端主機的 IP 地址,確認提交後即可看到相應的遠端主機和在上面執行的 Java 程式,連線成功後應該會顯示 Jstatd 及其 PID 。

右擊遠端 選擇新增遠端主機:

如果重新指定了jstatd埠,選擇高階設定修改埠,如下圖:預設埠為1099  

 

新增後如圖所示: 

 

三:Tomcat配置JMX 

用hostname -i 檢視是否為127.0.0.1,這步非常重要,否則會連線失敗,如果是,必須要配置-Djava.rmi.server.hostname 比如我的配置為 -Djava.rmi.server.hostname=192.168.8.7,而不需要修改hosts檔案,修改此檔案還可能影響到其他程式。 
只需要在TOMCAT_HOME/bin/找到catalina.sh 加上以下引數,重新啟動tomcat就可以了: 

JAVA_OPTS="$JAVA_OPTS -Djava.rmi.server.hostname=192.168.8.7  
-Dcom.sun.management.jmxremote.port=8088  
-Dcom.sun.management.jmxremote.ssl=false  
-Dcom.sun.management.jmxremote.authenticate=false"  

注:1. -Dcom.sun.management.jmxremote.port :這個是配置遠端 connection 的埠號的,要確定這個埠沒有被佔用

2. -Dcom.sun.management.jmxremote.ssl=false 指定了 JMX 是否啟用 ssl

3. -Dcom.sun.management.jmxremote.authenticate=false   指定了JMX 是否啟用鑑權(需要使用者名稱,密碼鑑權)

   2,3兩個是固定配置,是 JMX 的遠端服務許可權的

4. -Djava.rmi.server.hostname :這個是配置 server 的 IP 的

開啟JAVA_HOME/bin/下的jvisualvm 或者jconsole 的工具可以直接連線了,如下圖visualvm連線的示意圖: 

 也可以寫個Java類TestJMXClient.java測試下JMX連線是否成功:

import java.util.HashMap;  
import java.util.Map;  
  
import javax.management.MBeanServerConnection;  
import javax.management.remote.JMXConnector;  
import javax.management.remote.JMXConnectorFactory;  
import javax.management.remote.JMXServiceURL;  
  
/** 
 * @author Michael 
 */  
public class TestJMXClient {  
  
    /** 
     * @param args 
     */  
    public static void main(String[] args) {  
        try {  
            String jndiPath = "jmxrmi";  
            String serverhost = "192.168.8.7";  
            String serverport = "8088";  
            // url=service:jmx:rmi:///jndi/rmi://192.168.8.7:8088/jmxrmi  
            String jmxurl = "service:jmx:rmi:///jndi/rmi://" + serverhost + ":"  
                    + serverport + "/" + jndiPath;  
            System.out.println("jmxurl:" + jmxurl);  
            JMXServiceURL url = new JMXServiceURL(jmxurl);  
            Map<String, Object> enviMap = new HashMap<String, Object>();  
  
            JMXConnector connector = JMXConnectorFactory.connect(url, enviMap);  
  
            MBeanServerConnection mbsc = connector.getMBeanServerConnection();  
            System.out.println("successful connected ");  
            connector.close();  
            System.out.println("close connect");  
        } catch (Exception e) {  
            System.out.println("error");  
            e.printStackTrace();  
        }  
    }  
}  

 參考:

http://ihuangweiwei.iteye.com/blog/1219302

http://sjsky.iteye.com/blog/705323

http://www.cnblogs.com/wade-xu/p/4369094.html

http://www.cnblogs.com/leocook/p/jvisualvmandtomcat.html

http://blog.csdn.net/autfish/article/details/51326340

相關文章