posts - 156,  comments - 601,  trackbacks - 0
          公告
          <2013年2月>
          272829303112
          3456789
          10111213141516
          17181920212223
          242526272812
          3456789

          常用鏈接

          留言簿(45)

          隨筆分類(145)

          隨筆檔案(110)

          文章檔案(1)

          友情鏈接

          最新隨筆

          搜索

          •  

          積分與排名

          • 積分 - 679838
          • 排名 - 68

          最新評論

          閱讀排行榜

          評論排行榜

           

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

              但由于傳統(tǒng)的分析過程比較麻煩,需要使用Jdkjmap(Java Memory Map)命令把heap內(nèi)存dump到一個文件,然后用MAT進(jìn)行分析。所以本文介紹一種方法可以實(shí)現(xiàn)在線查看heap內(nèi)存的使用情況,并附上源碼實(shí)現(xiàn),希望對大家有幫助。由于目前調(diào)研中只找到了Sun JDK6以及以上版本的實(shí)現(xiàn),所以目前該方案只支持Sun JDK6或以上。如果其他同學(xué)有其它版本的JDK實(shí)現(xiàn)分享,歡迎一起交流。

          整體實(shí)現(xiàn)思路如下:

          1.       JDK6中在tools.jar類庫里有一個com.sun.tools.attach.VirtualMachine類,該類可以獲得JVM虛擬機(jī)的相關(guān)控制權(quán)限。

          2.       利用getPids.exe或其它工具獲取需要監(jiān)控的JVM pid進(jìn)程號信息

          3.       利用反射調(diào)用VirtualMachineattach方法,獲取VirtualMachine的實(shí)例對象

          4.       復(fù)用反射調(diào)用VirtualMachine實(shí)例的heapHisto方法,參數(shù)為 –all, 可獲到JVM的堆內(nèi)存信息

          5.       最后解析heapHisto方法返回的輸入流,讀取內(nèi)存數(shù)據(jù)即可獲得當(dāng)前JVM的堆內(nèi)存數(shù)據(jù)

          下面帖出的主要代碼來說明各步驟具體實(shí)現(xiàn)方法:

          JDK6中在tools.jar類庫里有一個com.sun.tools.attach.VirtualMachine類,該類可以獲得JVM虛擬機(jī)的相關(guān)控制權(quán)限。

              private static Class<?> findVirtualMachineClass() throws ClassNotFoundException,

                     MalformedURLException {

                 // JVM 虛擬機(jī)操作類

                 final String virtualMachineClassName = "com.sun.tools.attach.VirtualMachine";

                 try {

                     return Class.forName(virtualMachineClassName);

                 } catch (final ClassNotFoundException e) {

                     // exception ignored, try looking else where

                     File file = new File(System.getProperty("java.home"));

                     if ("jre".equalsIgnoreCase(file.getName())) {

                        file = file.getParentFile();

                     }

                     //直接從JDK lib目錄下加載 tools.jar類庫

                     final String[] defaultToolsLocation = { "lib", "tools.jar" };

                     for (final String name : defaultToolsLocation) {

                        file = new File(file, name);

                     }

                     final URL[] urls = { file.toURI().toURL() };

                     final ClassLoader cl = URLClassLoader.newInstance(urls);

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

                     return Class.forName(virtualMachineClassName, true, cl);

                 }

          }

           

          利用反射調(diào)用VirtualMachineattach方法,獲取VirtualMachine的實(shí)例對象

          本過程相對比較簡單,獲取VirtualMachine的類后,根據(jù)反射類,查詢attach方法

          //獲取JVM 虛擬機(jī)操作類后

          final Class<?> virtualMachineClass = findVirtualMachineClass();

          //根據(jù)反射查詢 attach方法,參數(shù)為String類型

          final Method attachMethod = virtualMachineClass.getMethod("attach", String.class);

          //通過 getpids.exe工具獲取當(dāng)前JVM進(jìn)程號

          final String pid = PID.getPID();

          try {

              //通過反射調(diào)用attache方法

              jvmVirtualMachine = invoke(attachMethod, null, pid);

          } finally {

              enabled = jvmVirtualMachine != null;

          }

           

          復(fù)用反射調(diào)用VirtualMachine實(shí)例的heapHisto方法,參數(shù)為 –all, 可獲到JVM的堆內(nèi)存信息

          本過程也是利用反射調(diào)用heapHisto方法,實(shí)現(xiàn)的代碼如下:

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

          //反射調(diào)用 heapHisto方法,參數(shù)為 -all

          final Method heapHistoMethod = virtualMachineClass.getMethod("heapHisto",

                 Object[].class);

          //該方面返回值為InputStream

          return (InputStream) invoke(heapHistoMethod, getJvmVirtualMachine(),

                             new Object[] { new Object[] { "-all" } });

           

           

          最后解析heapHisto方法返回的輸入流,讀取內(nèi)存數(shù)據(jù)即可獲得當(dāng)前JVM的堆內(nèi)存數(shù)據(jù), 通過該方法返回的一個文本內(nèi)容。

          Input Stream取出的結(jié)果(文本內(nèi)容)示例如下:

           

           num     #instances         #bytes class name

          ----------------------------------------------

             1:         14948        1892768 [C

             2:           958         567568 [B

             3:          1870         215584 <symbolKlass>

             4:          7366         176784 java.lang.String

             5:           132          88104 [I

             6:           841          86360 <constMethodKlass>

             7:           841          67672 <methodKlass>

             8:           968          61152 [Ljava.lang.Object;

             9:           101          48152 <constantPoolKlass>

            10:          2593          41488 java.lang.StringBuilder

            11:           101          40600 <instanceKlassKlass>

            12:           952          30464 java.util.TreeMap$Entry

            13:            79          25112 <constantPoolCacheKlass>

            14:           310          22280 [S

            15:           746          17904 sun.jvmstat.perfdata.monitor.AliasFileParser$Token

            16:           367          17616 java.nio.HeapCharBuffer

           

          Total         39840        3645336

           

          null

           

          因?yàn)閮?nèi)容太長,只截取了部分

          因?yàn)樽x取的是文本內(nèi)容,而且格式是完全固定的,所以大家可以直接解析里面的內(nèi)容。主要是后面三例,一個是實(shí)現(xiàn)的個數(shù),一個是實(shí)際的數(shù)據(jù)內(nèi)容,最后一個是實(shí)例關(guān)聯(lián)的類名稱.

           



           Good Luck!
           Yours Matthew!






          posted on 2013-02-20 16:30 x.matthew 閱讀(6338) 評論(9)  編輯  收藏 所屬分類: Best Practise(JDK API)
          主站蜘蛛池模板: 罗平县| 苏州市| 绵阳市| 手游| 谢通门县| 夏邑县| 肃宁县| 平乡县| 浦城县| 昌黎县| 奉贤区| 淮阳县| 高碑店市| 东兰县| 黎平县| 荔波县| 儋州市| 金塔县| 通渭县| 大理市| 邵东县| 荥阳市| 曲沃县| 乌什县| 麻江县| 尉氏县| 镶黄旗| 建水县| 无为县| 黄陵县| 罗源县| 德江县| 义乌市| 安平县| 登封市| 肇庆市| 石泉县| 连山| 五大连池市| 来凤县| 皋兰县|