利用jdk中工具完成Java程序監控方法記錄


轉載加自己整理的部分內容,轉載自:http://jiajun.iteye.com/blog/810150

記錄下JConsole使用方法

 一、JConsole是什么
    從Java 5開始 引入了 JConsole。JConsole 是一個內置 Java 性能分析器,可以從命令行或在 GUI shell 中運行。您可以輕松地使用 JConsole(或者,它更高端的 “近親” VisualVM )來監控 Java 應用程序性能和跟蹤 Java 中的代碼。
二、如何啟動JConsole
1.    如果是從命令行啟動,使 JDK 在 PATH 上,運行 jconsole 即可。
2.    如果從 GUI shell 啟動,找到 JDK 安裝路徑,打開 bin 文件夾,雙擊 jconsole 。
    當分析工具彈出時(取決於正在運行的 Java 版本以及正在運行的 Java 程序數量),可能會出現一個對話框,要求輸入一個進程的 URL 來連接,也可能列出許多不同的本地 Java 進程(有時包含 JConsole 進程本身)來連接。如圖所示:
 
想分析那個程序就雙擊那個進程。
三、如何設置JAVA程序運行時可以被JConsolse連接分析
1.    本地程序(相對於開啟JConsole的計算機),無需設置任何參數就可以被本地開啟的JConsole連接(Java SE 6開始無需設置,之前還是需要設置運行時參數 -Dcom.sun.management.jmxremote )
2.    無認證連接 (下面的設置表示:連接的端口為8999、無需認證就可以被連接)

如下這些參數需要設置為虛擬機運行參數不是程序運行參數
1).    -Dcom.sun.management.jmxremote
2).    -Dcom.sun.management.jmxremote.port=8999 \  
3).    -Dcom.sun.management.jmxremote.authenticate=false \  
4).    -Dcom.sun.management.jmxremote.ssl=false  


3.    如果考慮到安全因素,需要認證,需要安全連接,也是可以搞定的。參考:http://download.oracle.com/javase/6/docs/technotes/guides/management/agent.html#gdenv
四、JConsole如何連接遠程機器的JAVA程序(舉例說明)
1、寫一個簡單的一直運行的JAVA程序,運行在某台機器上如(192.168.0.181)
1).    java -cp . -Dcom.sun.management.jmxremote.port=8999 -Dcom.sun.managent.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false JConsoleTest  
 
2、另外一台機器進行連接
可以直接使用命令:
1).    jconsole.exe 192.168.0.181:8999  
 也可以在已經打開的JConsole界面操作 連接->新建連接->選擇遠程進程->輸入遠程主機IP和端口號->點擊“連接”,如圖:
 
 然后就會進入分析界面:
性能分析
下面說說如何分析,如何使用這六個標簽
•    概述: Displays overview information about the Java VM and monitored values.
•    內存: 顯示內存使用信息
•    線程: 顯示線程使用信息
•    類: 顯示類裝載信息
•    *VM摘要:*顯示java VM信息
•    MBeans: 顯示 MBeans.
概述
 
 
    概述很簡單沒啥說的,自己看看吧,不過值得一提的是對着圖點擊右鍵可以保存數據到CSV文件,以后可以使用其他工具來分析這些數據。
內存
 
    這個比較有價值,參看堆內存,非堆內存,內存池的狀況總體內存的分配和使用情況以及不同的GC進行垃圾回收的次數和時間。可以手動進行GC查看內存變化。
 
   在分析JAVA內存問題進行調優時候非常有用,你要學習JVM內存模型,之后會發現這里的每個值都具有意義。
 
   GC的算法和參數對性能有顯著的影響,注意垃圾回收次數、時間、以及partial GC和full GC,調整你所使用的不同GC和以及各個GC下的參數,然后在這個視圖下觀察,以得到好的性能。
 
這里貼一下 Java HotSpot VM garbage collector 下generational GC 的各代的划分圖:
 
關於GC,可以參考:http://www.oracle.com/technetwork/java/gc-tuning-5-138395.html
線程
 
    左下角顯示所有的活動線程(如果線程過多,可以在下面的過濾欄中輸入字符串過濾出你想要觀察的線程)。點擊某個顯示會顯示這個線程的名稱、狀態、阻塞和等待的次數、堆棧的信息。
 
    統計圖顯示的是線程數目的峰值(紅色)和當前活動的線程(藍色)。
 
   另外下面有個按鈕“檢測到死鎖”,有時候會有用處。

 
沒啥要說的。
VM摘要
 
也沒啥要說的,看看吧,內存狀況,操作系統...
Mbean
一個MBean是一個被管理的Java對象,有點類似於JavaBean,一個設備、一個應用或者任何資源都可以被表示為MBean,MBean會暴露一個接口對外,這個接口可以讀取或者寫入一些對象中的屬性。Mbean實現類需要注冊如相應MbeanServer中,才可以在JConsole工具中查看相應接口信息。
 
這里可以有一些額外的操作。
使用插件
1).    jconsole -pluginpath C:\Java\jdk1.6.0_22\demo\management\JTop\JTop.jar  
 

 

 

JMX及MBean講解與使用,

轉載自:https://www.cnblogs.com/dongguacai/p/5900507.html

 

一、JMX的定義  

  JMX(Java Management Extensions)是一個為應用程序植入管理功能的框架。JMX是一套標准的代理和服務,實際上,用戶可以在任何Java應用程序中使用這些代理和服 務實現管理。這是官方文檔上的定義,我看過很多次也無法很好的理解。我個人的理解是JMX讓程序有被管理的功能,例如你開發一個WEB網站,它是在24小 時不間斷運行,那么你肯定會對網站進行監控,如每天的UV、PV是多少;又或者在業務高峰的期間,你想對接口進行限流,就必須去修改接口並發的配置值。

  應用場景:中間件軟件WebLogic的管理頁面就是基於JMX開發的,而JBoss則整個系統都基於JMX構架。

對於一些參數的修改,網上有一段描述還是比較形象的:

1、程序初哥一般是寫死在程序中,到要改變的時候就去修改代碼,然后重新編譯發布。

2、程序熟手則配置在文件中(JAVA一般都是properties文件),到要改變的時候只要修改配置文件,但還是必須重啟系統,以便讀取配置文件里最新的值。

3、程序好手則會寫一段代碼,把配置值緩存起來,系統在獲取的時候,先看看配置文件有沒有改動,如有改動則重新從配置里讀取,否則從緩存里讀取。

4、程序高手則懂得物為我所用,用JMX把需要配置的屬性集中在一個類中,然后寫一個MBean,再進行相關配置。另外JMX還提供了一個工具頁,以方便我們對參數值進行修改。

二、JMX架構圖:

從圖中我們可以看到,JMX的結構一共分為三層:

1、基礎層:主要是MBean,被管理的資源。

MBean分為如下四種,我接下來主要介紹standard MBean

類型 描述
standard MBean 這種類型的MBean最簡單,它能管理的資源(包括屬性,方法,時間)必須定義在接口中,然后MBean必須實現這個接口。它的命名也必須遵循一定的規范,例如我們的MBean為Hello,則接口必須為HelloMBean。
dynamic MBean 必須實現javax.management.DynamicMBean接口,所有的屬性,方法都在運行時定義
open MBean 此MBean的規范還不完善,正在改進中
model MBean 與標准和動態MBean相比,你可以不用寫MBean類,只需使用 javax.management.modelmbean.RequiredModelMBean即可。RequiredModelMBean實現了 ModelMBean接口,而ModelMBean擴展了DynamicMBean接口,因此與DynamicMBean相似,Model MBean的管理資源也是在運行時定義的。與DynamicMBean不同的是,DynamicMBean管理的資源一般定義在DynamicMBean 中(運行時才決定管理那些資源),而model MBean管理的資源並不在MBean中,而是在外部(通常是一個類),只有在運行時,才通過set方法將其加入到model MBean中。后面的例子會有詳細介紹

2、適配層:MBeanServer,主要是提供對資源的注冊和管理。

3、接入層:提供遠程訪問的入口。

 

接下來我這里會用程序來介紹三種訪問JMX的方式:

三、JDK的小工具Jconsole訪問

 1、 首先定義一個MBean接口,接口的命名規范為以具體的實現類為前綴(這個規范很重要)

復制代碼
 1 package jmx;  2  3 public interface HelloMBean  4 {  5 public String getName();  6  7 public void setName(String name);  8  9 public String getAge(); 10 11 public void setAge(String age); 12 13 public void helloWorld(); 14 15 public void helloWorld(String str); 16 17 public void getTelephone(); 18 }
復制代碼

2、定義一個實現類,實現上面的接口:

復制代碼
 1 package jmx;  2  3 /*  4  * 該類名稱必須與實現的接口的前綴保持一致(即MBean前面的名稱  5 */  6 public class Hello implements HelloMBean  7 {  8 private String name;  9 10 private String age; 11 12 public void getTelephone() 13  { 14 System.out.println("get Telephone"); 15  } 16 17 public void helloWorld() 18  { 19 System.out.println("hello world"); 20  } 21 22 public void helloWorld(String str) 23  { 24 System.out.println("helloWorld:" + str); 25  } 26 27 public String getName() 28  { 29 System.out.println("get name 123"); 30 return name; 31  } 32 33 public void setName(String name) 34  { 35 System.out.println("set name 123"); 36 this.name = name; 37  } 38 39 public String getAge() 40  { 41 System.out.println("get age 123"); 42 return age; 43  } 44 45 public void setAge(String age) 46  { 47 System.out.println("set age 123"); 48 this.age = age; 49  } 53 }
復制代碼

3、定義agent層:

復制代碼
 1 package jmx;  2  3 import java.lang.management.ManagementFactory;  4  5 import javax.management.JMException;  6 import javax.management.MBeanServer;  7 import javax.management.ObjectName;  8  9 public class HelloAgent 10 { 11 public static void main(String[] args) throws JMException, Exception 12  { 13 MBeanServer server = ManagementFactory.getPlatformMBeanServer(); 14 ObjectName helloName = new ObjectName("jmxBean:name=hello"); 15 //create mbean and register mbean 16 server.registerMBean(new Hello(), helloName); 17 Thread.sleep(60*60*1000); 18  } 19 }
復制代碼

1、其中第13行是通過工廠類獲取MBeanServer,用來做MBean的容器 。

2、第14行中的ObjectName中的取名是有一定規范的,格式為:“域名:name=MBean名稱”,其中域名和MBean的名稱可以任意取。這樣定義后,就可以唯一標識我們定義的這個MBean的實現類了。

3、第16行是將Hello這個類注入到MBeanServer中,注入需要創建一個ObjectName類 

這樣,一個簡單的JMX的DEMO已經寫完了,現在我們通過JDK提供的Jconsole來進行操作。

1、首先在自己的本地路徑下:C:\Program Files (x86)\Java\jdk1.6.0_43\bin找到jconsole.exe這個小工具,雙擊打開:

2、雙擊打開我們的本地進程:HelloAgent:

3.在這個界面上,我們可以給程序中HelloMBean的屬性賦值,也可以調用其中的方法:

4、控制台打印如下:

四、通過JMX提供的工具頁訪問

這里,我們復用上面的接口和實現類,只需要改動適配層,這里需要到導入外部jar包jdmk

復制代碼
package jmx; import java.lang.management.ManagementFactory; import javax.management.JMException; import javax.management.MBeanServer; import javax.management.ObjectName; import com.sun.jdmk.comm.HtmlAdaptorServer; public class HelloAgent { public static void main(String[] args) throws JMException, Exception { MBeanServer server = ManagementFactory.getPlatformMBeanServer(); ObjectName helloName = new ObjectName("jmxBean:name=hello"); //create mbean and register mbean server.registerMBean(new Hello(), helloName); ObjectName adapterName = new ObjectName("HelloAgent:name=htmladapter,port=8082"); HtmlAdaptorServer adapter = new HtmlAdaptorServer(); server.registerMBean(adapter, adapterName); adapter.start(); } }
復制代碼

我們訪問地址:http://localhost:8082,點擊name=hello:

1、在這里創建一個AdaptorServer,這個類將決定MBean的管理界面,這里用最普通的Html型界面。AdaptorServer其實也是一個MBean。 

2、我們可以看到這個工具頁,其實與我們上一個案例中的Jconsole中的管理界面類似,都可以操作資源中的屬性和方法。

五、通過客戶端程序進行遠程訪問

 1、這里需要對agent進行修改,增加ip和porta綁定部分的邏輯

復制代碼
package jmxTest; import java.io.IOException; import java.lang.management.ManagementFactory; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import javax.management.JMException; import javax.management.MBeanServer; import javax.management.ObjectName; import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXServiceURL; public class HelloAgent { public static void main(String[] args) throws JMException, NullPointerException { MBeanServer server = ManagementFactory.getPlatformMBeanServer(); ObjectName helloName = new ObjectName("jmxBean:name=hello"); //create mbean and register mbean server.registerMBean(new Hello(), helloName); try { //這個步驟很重要,注冊一個端口,綁定url后用於客戶端通過rmi方式連接JMXConnectorServer LocateRegistry.createRegistry(9999); //URL路徑的結尾可以隨意指定,但如果需要用Jconsole來進行連接,則必須使用jmxrmi JMXServiceURL url = new JMXServiceURL ("service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi"); JMXConnectorServer jcs = JMXConnectorServerFactory.newJMXConnectorServer(url, null, server); System.out.println("begin rmi start"); jcs.start(); System.out.println("rmi start"); } catch (RemoteException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } 
}
}
復制代碼

  寫到這里,如果沒有client進行遠程連接,可以使用Jconsole進行遠程訪問:

2、客戶端Client程序,用於與agent進行遠程連接:

復制代碼
 1 package jmx;  2  3 import java.io.IOException;  4  5 import javax.management.Attribute;  6 import javax.management.MBeanServerConnection;  7 import javax.management.MBeanServerInvocationHandler;  8 import javax.management.ObjectName;  9 import javax.management.remote.JMXConnector; 10 import javax.management.remote.JMXConnectorFactory; 11 import javax.management.remote.JMXServiceURL; 12 13 14 public class Client 15 { 16 public static void main(String[] args) throws IOException, Exception, NullPointerException 17  { 18 JMXServiceURL url = new JMXServiceURL 19 ("service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi"); 20 JMXConnector jmxc = JMXConnectorFactory.connect(url,null); 21 22 MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); 23 //ObjectName的名稱與前面注冊時候的保持一致 24 ObjectName mbeanName = new ObjectName("jmxBean:name=hello"); 25 26 System.out.println("Domains ......"); 27 String[] domains = mbsc.getDomains(); 28 29 for(int i=0;i<domains.length;i++) 30  { 31 System.out.println("doumain[" + i + "]=" + domains[i] ); 32  } 33 34 System.out.println("MBean count = " + mbsc.getMBeanCount()); 35 //設置指定Mbean的特定屬性值 36 //這里的setAttribute、getAttribute操作只能針對bean的屬性 37 //例如對getName或者setName進行操作,只能使用Name,需要去除方法的前綴 38 mbsc.setAttribute(mbeanName, new Attribute("Name","杭州")); 39 mbsc.setAttribute(mbeanName, new Attribute("Age","1990")); 40 String age = (String)mbsc.getAttribute(mbeanName, "Age"); 41 String name = (String)mbsc.getAttribute(mbeanName, "Name"); 42 System.out.println("age=" + age + ";name=" + name); 43 44 HelloMBean proxy = MBeanServerInvocationHandler. 45 newProxyInstance(mbsc, mbeanName, HelloMBean.class, false); 46  proxy.helloWorld(); 47 proxy.helloWorld("migu"); 48  proxy.getTelephone(); 49 //invoke調用bean的方法,只針對非設置屬性的方法 50 //例如invoke不能對getName方法進行調用 51 mbsc.invoke(mbeanName, "getTelephone", null, null); 52 mbsc.invoke(mbeanName, "helloWorld", 53 new String[]{"I'll connect to JMX Server via client2"}, new String[]{"java.lang.String"}); 54 mbsc.invoke(mbeanName, "helloWorld", null, null); 55  } 56 }
復制代碼

a、在35到41行,是對屬性進行賦值和取值,這里我們不能直接調用方法,而是通過setAttribute、getAttrubute方法來進行操作,則屬性的首字母要大寫。

b、對資源里面的方法進行操作有兩種方式:一是通過代理直接調用方法;二是通過JAVA的反射注入的方式進行方法的調用。

下面我們來看看執行結果,先執行agent,再執行客戶端:

c、client的控制台打印結果:

 

d、agent控制台打印結果:

 六、Notification

 MBean之間的通信是必不可少的,Notification就起到了在MBean之間溝通橋梁的作用。JMX 的通知由四部分組成:

1、Notification這個相當於一個信息包,封裝了需要傳遞的信息

2、Notification broadcaster這個相當於一個廣播器,把消息廣播出。

3、Notification listener 這是一個監聽器,用於監聽廣播出來的通知信息。

4、Notification filiter 這個一個過濾器,過濾掉不需要的通知。這個一般很少使用。

這里我們使用日常打招呼的場景:jack與我偶遇,jack說:hi;我禮貌的回答:hello,jack。

這里我們先分別創建兩個資源:

復制代碼
package jmx; /* * 該類名稱必須與實現的接口的前綴保持一致(即MBean前面的名稱 */ public class Hello implements HelloMBean { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public void printHello() { System.out.println("Hello World, " + name); } public void printHello(String whoName) { System.out.println("Hello , " + whoName); } }
復制代碼
復制代碼
package jmx; /* * 接口名必須以MBean結尾 */ public interface HelloMBean { public String getName(); public void setName(String name); public void printHello(); public void printHello(String whoName); }
復制代碼
復制代碼
package jmx; import javax.management.Notification; import javax.management.NotificationBroadcasterSupport; public class Jack extends NotificationBroadcasterSupport implements JackMBean { private int seq = 0; public void hi() { //創建一個信息包 Notification notify = //通知名稱;誰發起的通知;序列號;發起通知時間;發送的消息 new Notification("jack.hi",this,++seq,System.currentTimeMillis(),"jack"); sendNotification(notify); } }
復制代碼
復制代碼
package jmx; public interface JackMBean { public void hi(); }
復制代碼

這里的類Jack不僅實現了MBean接口,還繼承了NotificationBroadcasterSupport。jack在這里創建並發送了一個消息包。

復制代碼
package jmx; import javax.management.Notification; import javax.management.NotificationListener; public class HelloListener implements NotificationListener { public void handleNotification(Notification notification, Object handback) { if(handback instanceof Hello) { Hello hello = (Hello)handback; hello.printHello(notification.getMessage()); } } }
復制代碼
復制代碼
package jmx; import java.lang.management.ManagementFactory; import javax.management.JMException; import javax.management.MBeanServer; import javax.management.ObjectName; public class HelloAgent { public static void main(String[] args) throws JMException, Exception { MBeanServer server = ManagementFactory.getPlatformMBeanServer(); ObjectName helloName = new ObjectName("yunge:name=Hello"); Hello hello=new Hello(); server.registerMBean(hello, helloName); Jack jack = new Jack(); server.registerMBean(jack, new ObjectName("jack:name=Jack")); jack.addNotificationListener(new HelloListener(), null, hello); Thread.sleep(500000); } }
復制代碼

我們用Jconsole來進行訪問:

這里我們可以看到有兩個MBean,一個是yunge,一個是jack。我們執行jack的hi方法后,去看下控制台上的打印信息;

 七、linux下利用JMX監控Tomcat

  利用JMX監控Tomcat,就是相當於部署在tomcat上的應用作為服務端,也就是被管理資源的對象。然后通過程序或者jconsole遠程連接到該應用上來。遠程連接需要服務器端提供ip和port。如果需要加密訪問的話,還需要配置用戶名、密碼等參數。

主要是在tomcat下的文件catalina.sh中進行一些環境變量的配置配置:

 

-Dcom.sun.management.jmxremote=true                 相關 JMX 代理偵聽開關

-Djava.rmi.server.hostname                                     服務器端的IP
-Dcom.sun.management.jmxremote.port=29094             相關 JMX 代理偵聽請求的端口

-Dcom.sun.management.jmxremote.ssl=false              指定是否使用 SSL 通訊

-Dcom.sun.management.jmxremote.authenticate=false     指定是否需要密碼驗證

這樣就可以通過客戶端或者jconsole對tomcat進行監控。

 

整理jvm其他工具及部分參數

JVM小工具

在${JAVA_HOME}/bin/目錄下Sun/Oracle給我們提供了一些處理應用程序性能問題、定位故障的工具, 包含

bin 描述 功能
jps 打印Hotspot VM進程 VMID、JVM參數、main()函數參數、主類名/Jar路徑
jstat 查看Hotspot VM 運行時信息 類加載、內存、GC[可分代查看]、JIT編譯
jinfo 查看和修改虛擬機各項配置 -flag name=value
jmap heapdump: 生成VM堆轉儲快照、查詢finalize執行隊列、Java堆和永久代詳細信息 jmap -dump:live,format=b,file=heap.bin [VMID]
jstack 查看VM當前時刻的線程快照: 當前VM內每一條線程正在執行的方法堆棧集合 Thread.getAllStackTraces()提供了類似的功能
javap 查看經javac之后產生的JVM字節碼代碼 自動解析.class文件, 避免了去理解class文件格式以及手動解析class文件內容
jcmd 一個多功能工具, 可以用來導出堆, 查看Java進程、導出線程信息、 執行GC、查看性能相關數據等 幾乎集合了jps、jstat、jinfo、jmap、jstack所有功能
jconsole 基於JMX的可視化監視、管理工具 可以查看內存、線程、類、CPU信息, 以及對JMX MBean進行管理
jvisualvm JDK中最強大運行監視和故障處理工具 可以監控內存泄露、跟蹤垃圾回收、執行時內存分析、CPU分析、線程分析…

VM常用參數整理

參數 描述
-Xms 最小堆大小
-Xmx 最大堆大小
-Xmn 新生代大小
-XX:PermSize 永久代大小
-XX:MaxPermSize 永久代最大大小
-XX:+PrintGC 輸出GC日志
-verbose:gc -
-XX:+PrintGCDetails 輸出GC的詳細日志
-XX:+PrintGCTimeStamps 輸出GC時間戳(以基准時間的形式)
-XX:+PrintHeapAtGC 在進行GC的前后打印出堆的信息
-Xloggc:/path/gc.log 日志文件的輸出路徑
-XX:+PrintGCApplicationStoppedTime 打印由GC產生的停頓時間


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM