中文JAVA技术平等自由协作创造

Java专题文章博客和开源

常用链接

统计

最新评论

源码实现实时获取Java堆内存信息

  如果大家有遇到过Java内存泄露问题,而且亲自动手去定位和分析经历的同学来讲,获取Java的堆内信息对了内存使用情况的问题分析和定位是非常有帮助了。例如我们常用的MAT工具,可以较方便的让我们定位程序中内存的使用情况,是哪块导致了内存的泄露等。

  但由于传统的分析过程比较麻烦,需要使用Jdk的jmap(Java Memory Map)命令把heap内存dump到一个文件,然后用MAT进行分析。所以本文介绍一种方法可以实现在线查看heap内存的使用情况,并附上源码实现,希望对大家有帮助。由于目前调研中只找到了Sun JDK6以及以上版本的实现,所以目前该方案只支持Sun JDK6或以上。如果其他同学有其它版本的JDK实现分享,欢迎一起交流。

  整体实现思路如下:

  1.       JDK6中在tools.jar类库里有一个com.sun.tools.attach.VirtualMachine类,该类可以获得JVM虚拟机的相关控制权限证券从业代考 期货从业代考

  2.       利用getPids.exe或其它工具获取需要监控的JVM 的pid进程号信息

  3.       利用反射调用VirtualMachine的attach方法,获取VirtualMachine的实例对象

  4.       复用反射调用VirtualMachine实例的heapHisto方法,参数为 –all, 可获到JVM的堆内存信息

  5.       最后解析heapHisto方法返回的输入流,读取内存数据即可获得当前JVM的堆内存数据会计从业代考 注册会计师代考

  下面帖出的主要代码来说明各步骤具体实现方法:

  l JDK6中在tools.jar类库里有一个com.sun.tools.attach.VirtualMachine类,该类可以获得JVM虚拟机的相关控制权限。

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

  MalformedURLException {

  // JVM 虚拟机操作类

  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虚拟机操作类

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

  }

  }

  l 利用反射调用VirtualMachine的attach方法,获取VirtualMachine的实例对象

  本过程相对比较简单,获取VirtualMachine的类后,根据反射类,查询attach方法

  //获取JVM 虚拟机操作类后

  final Class<?> virtualMachineClass = findVirtualMachineClass();

  //根据反射查询 attach方法,参数为String类型

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

  //通过 getpids.exe工具获取当前JVM进程号

  final String pid = PID.getPID();

  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 = virtualMachineClass.getMethod("heapHisto",

  Object[].class);

  //该方面返回值为InputStream

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

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

  l 最后解析heapHisto方法返回的输入流,读取内存数据即可获得当前JVM的堆内存数据, 通过该方法返回的一个文本内容护士代考 心理咨询师代考

  Input Stream取出的结果(文本内容)示例如下:

  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

  因为内容太长,只截取了部分

  因为读取的是文本内容,而且格式是完全固定的,所以大家可以直接解析里面的内容。主要是后面三例,一个是实现的个数,一个是实际的数据内容,最后一个是实例关联的类名称。

posted on 2013-03-12 20:32 好不容易 阅读(202) 评论(0)  编辑  收藏


只有注册用户登录后才能发表评论。


网站导航:
 
PK10开奖 PK10开奖