在一個Java企業環境中,可能會存在這樣那樣和類相關的情況,比如類沖突(classloader加載的類不是我們所需要的),perm gen內存泄漏等。出現這樣的情況,我們可能需要打開verbose class來trace class的load、unload情況。通過打開verbose class的格式如下:
java %JAVA_OPTIONS% %MEM_ARGS% -verbose:class MainClass >tmp.out 2>&1
上述這種方法需要我們重新啟動服務器,比如Tomcat、Weblogic等。但如果我們運行的是一個生產系統,重啟不是個好的方法。那么除了上述方法,我們能否在不重啟服務器的情況下動態打開、關閉verbose class呢?
JDK的MBean為我們提供了這樣的接口,我們可以通過這樣的MBean來實現上述需求。MBean提供了大量JVM管理的接口,比如Memory、GarbageCollector、ClassLoading、Thread、Runtime等,更詳細的信息可以參考
javax.management的API。下面我們看看如果通過程序的方式attach上target JVM,然后打開verbose class。
對于attach到target jvm我們可以使用如下兩種方式:
1:根據process id,即pid
如何獲取pid呢?
Windows: netstat -abn | find "7001", 7001是服務器的listening port
Linux/Unix: ps -ef | grep java
1 public MBeanServerConnection getMBeanServerConnection(long pid)
2 {
3 MBeanServerConnection serviceConnection = null;
4 VirtualMachine vm = null;
5 try
6 {
7 vm = VirtualMachine.attach(String.valueOf(pid));
8 String connectorAddress =
9 vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);
10 if (connectorAddress == null) {
11 String agent = vm.getSystemProperties().getProperty("java.home") +
12 File.separator + "lib" + File.separator + "management-agent.jar";
13 vm.loadAgent(agent);
14 connectorAddress = vm.getAgentProperties().getProperty(CONNECTOR_ADDRESS);
15 }
16 if(connectorAddress == null)
17 System.exit(1);
18 serviceConnection = getMBeanServerConnection(connectorAddress);
19 }catch(Exception e){}
20 return serviceConnection;
21 }
2:remote management的listening address及listening port
為了啟用remote managed port,我們需要在服務器的啟動腳本中加入如下內容,如果你覺得不做驗證、non-ssl很不爽,你可以使用SSL及password file做認證,具體可以參考:http://www.j2ee.me/j2se/1.5.0/docs/guide/management/agent.html
set JAVA_OPTIONS=-Dcom.sun.management.jmxremote.port=9192 %JAVA_OPTIONS%
set JAVA_OPTIONS=-Dcom.sun.management.jmxremote.authenticate=false %JAVA_OPTIONS%
set JAVA_OPTIONS=-Dcom.sun.management.jmxremote.ssl=false %JAVA_OPTIONS%
1 public MBeanServerConnection getMBeanServerConnection(String hostname, String listeningPort)
2 {
3 MBeanServerConnection conn = null;
4 try{
5 url = "service:jmx:rmi:///jndi/rmi://"+host+":"+port+"/jmxrmi";
6 JMXServiceURL serviceURL = new JMXServiceURL(url);
7 connector = JMXConnectorFactory.connect(serviceURL);
8 conn = connector.getMBeanServerConnection();
9 }catch(Exception e){
10 e.printStackTrace();
11 }
12 return conn;
13 }
好了,我們拿到MBeanServerConnection后,說明我們已經attach到target JVM了,有了這個連接,我們可以為所欲為了,夸張了點哈。下面以classloading mbean為例,看看我們如何操作這樣的MBean,如果從這些MBean信息,
1 private void checkClassLoadingInfo(MBeanServerConnection conn)
2 {
3 try
4 {
5 clMBean = (ClassLoadingMXBean)ManagementFactory.
6 newPlatformMXBeanProxy(conn, ManagementFactory.CLASS_LOADING_MXBEAN_NAME, ClassLoadingMXBean.class);
7 }catch(IOException ioe){}
8 System.out.println(clMBean.getTotalLoadedClassCount());
9 System.out.println(clMBean.getLoadedClassCount());
10 System.out.println(clMBean.getUnloadedClassCount());
11 //here we can turn on verbose of class loading dynamically
12 clMBean.setVerbose(true);
13 }
打開verbose class后,我們就可以看到class loading\unloading相關的信息了,如下:
[Loaded weblogic.servlet.FileServlet from file:/D:/beasys/wls1030/wlserver_10.3/server/lib/weblogic.jar]
[Loaded weblogic.utils.string.CachingDateFormat$ParseCacheHolder from file:/D:/beasys/wls1030/modules/com.bea.core.utils_1.4.0.0.jar]
[Loaded java.lang.StringIndexOutOfBoundsException from d:\beasys\wls1030\JDK160~1\jre\lib\rt.jar]
有了這些信息,我們就可以根據他們診斷類沖突之類的問題。如果需要關閉verbose class,直接在上面的程序中調用setVerbose(false)就可以了。
正如前面所說的那樣,這樣的Mbean有很多,具體的需要你參考JDK的management API。
posted on 2009-09-08 09:46
走走停停又三年 閱讀(2926)
評論(0) 編輯 收藏 所屬分類:
Java Technology