熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java核心技術 >> 正文

源碼實現實時獲取Java堆內存信息

2013-11-23 19:08:08  來源: Java核心技術 

  如果大家有遇到過Java內存洩露問題而且親自動手去定位和分析經歷的同學來講獲取Java的堆內信息對了內存使用情況的問題分析和定位是非常有幫助了例如我們常用的MAT工具可以較方便的讓我們定位程序中內存的使用情況是哪塊導致了內存的洩露等

  但由於傳統的分析過程比較麻煩需要使用Jdk的jmap(Java Memory Map)命令把heap內存dump到一個文件然後用MAT進行分析所以本文介紹一種方法可以實現在線查看heap內存的使用情況並附上源碼實現希望對大家有幫助由於目前調研中只找到了Sun JDK以及以上版本的實現所以目前該方案只支持Sun JDK或以上如果其他同學有其它版本的JDK實現分享歡迎一起交流

  整體實現思路如下

         JDK中在toolsjar類庫裡有一個comsuntoolsattachVirtualMachine類該類可以獲得JVM虛擬機的相關控制權限

         利用getPidsexe或其它工具獲取需要監控的JVM 的pid進程號信息

         利用反射調用VirtualMachine的attach方法獲取VirtualMachine的實例對象

         復用反射調用VirtualMachine實例的heapHisto方法參數為 –all 可獲到JVM的堆內存信息

         最後解析heapHisto方法返回的輸入流讀取內存數據即可獲得當前JVM的堆內存數據

  下面帖出的主要代碼來說明各步驟具體實現方法

  l JDK中在toolsjar類庫裡有一個comsuntoolsattachVirtualMachine類該類可以獲得JVM虛擬機的相關控制權限

  private static Class<?> findVirtualMachineClass() throws ClassNotFoundException

  MalformedURLException {

  // JVM 虛擬機操作類

  final String virtualMachineClassName = comsuntoolsattachVirtualMachine;

  try {

  return ClassforName(virtualMachineClassName)

  } catch (final ClassNotFoundException e) {

  // exception ignored try looking else where

  File file = new File(SystemgetProperty(javahome))

  if (jreequalsIgnoreCase(filegetName())) {

  file = filegetParentFile()

  }

  //直接從JDK的 lib目錄下加載 toolsjar類庫

  final String[] defaultToolsLocation = { lib toolsjar };

  for (final String name : defaultToolsLocation) {

  file = new File(file name)

  }

  final URL[] urls = { filetoURI()toURL() };

  final ClassLoader cl = URLClassLoadernewInstance(urls)

  //再次嘗試反射查詢 JVM虛擬機操作類

  return ClassforName(virtualMachineClassName true cl)

  }

  }

  l 利用反射調用VirtualMachine的attach方法獲取VirtualMachine的實例對象

  本過程相對比較簡單獲取VirtualMachine的類後根據反射類查詢attach方法

  //獲取JVM 虛擬機操作類後

  final Class<?> virtualMachineClass = findVirtualMachineClass()

  //根據反射查詢 attach方法參數為String類型

  final Method attachMethod = virtualMachineClassgetMethod(attach Stringclass)

  //通過 getpidsexe工具獲取當前JVM進程號

  final String pid = PIDgetPID()

  try {

  //通過反射調用attache方法

  jvmVirtualMachine = invoke(attachMethod null pid)

  } finally {

  enabled = jvmVirtualMachine != null;

  }

  l 復用反射調用VirtualMachine實例的heapHisto方法參數為 –all 可獲到JVM的堆內存信息

  本過程也是利用反射調用heapHisto方法實現的代碼如下

  final Class<?> virtualMachineClass = getJvmVirtualMachine()getClass()

  //反射調用 heapHisto方法參數為 all

  final Method heapHistoMethod = virtualMachineClassgetMethod(heapHisto

  Object[]class)

  //該方面返回值為InputStream

  return (InputStream) invoke(heapHistoMethod getJvmVirtualMachine()

  new Object[] { new Object[] { all } })

  l 最後解析heapHisto方法返回的輸入流讀取內存數據即可獲得當前JVM的堆內存數據 通過該方法返回的一個文本內容

  Input Stream取出的結果(文本內容)示例如下

  num     #instances         #bytes class name

  

  :                 [C

  :                    [B

  :                   <symbolKlass>

  :                   javalangString

  :                     [I

  :                     <constMethodKlass>

  :                     <methodKlass>

  :                     [LjavalangObject;

  :                     <constantPoolKlass>

  :                    javalangStringBuilder

  :                     <instanceKlassKlass>

  :                     javautilTreeMap$Entry

  :                      <constantPoolCacheKlass>

  :                     [S

  :                     sunjvmstatperfdatamonitorAliasFileParser$Token

  :                     javanioHeapCharBuffer

  Total                

  null

  因為內容太長只截取了部分

  因為讀取的是文本內容而且格式是完全固定的所以大家可以直接解析裡面的內容主要是後面三例一個是實現的個數一個是實際的數據內容最後一個是實例關聯的類名稱


From:http://tw.wingwit.com/Article/program/Java/hx/201311/26337.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.