`

转:实现实时获取Java堆内存信息

阅读更多

 

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

    但由于传统的分析过程比较麻烦,需要使用Jdkjmap(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.       利用反射调用VirtualMachineattach方法,获取VirtualMachine的实例对象

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

5.       最后解析heapHisto方法返回的输入流,读取内存数据即可获得当前JVM的堆内存数据

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

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

    private static Class<?> findVirtualMachineClass() throwsClassNotFoundException,

           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);

       }

}

 

利用反射调用VirtualMachineattach方法,获取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;

}

 

复用反射调用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" } });

 

 

最后解析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

 

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

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

 



 Good Luck!
 Yours Matthew!






posted on 2013-02-20 16:30 x.matthew 阅读(1715) 评论(6)  编辑  收藏 所属分类: Best Practise(JDK API)
分享到:
评论

相关推荐

    Java获取计算机CPU、内存等信息

    以下代码展示了如何获取总的物理内存和Java堆内存的信息: ```java import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; import java.lang.management.MemoryUsage; ...

    java获取cpu、内存信息

    在Java编程中,获取CPU和内存信息是系统监控和性能分析的重要部分。下面将详细介绍如何使用Java来实现这一目标。 首先,我们从CPU信息开始。Java提供了`java.lang.management`包,该包中的`OperatingSystemMXBean`...

    java-sizeof-0.0.4:一个查看java对象占用内存大小

    在Java中,内存主要分为堆内存(Heap)和栈内存(Stack)。对象通常存储在堆内存中,而基本类型的变量和方法的局部变量存储在栈内存中。堆内存的大小可动态扩展,而栈内存的大小在编译时就已经确定。了解对象占用的...

    java中获取CPU 内存的方法

    // 获取Java堆内存信息 Runtime runtime = Runtime.getRuntime(); monitorInfo.setTotalMemory(runtime.totalMemory()); monitorInfo.setFreeMemory(runtime.freeMemory()); monitorInfo.setMaxMemory(runtime....

    java获取系统信息的类文件

    4. **`java.lang.management.MemoryMXBean`**: 提供了对JVM内存管理的访问,包括堆内存和非堆内存的信息。`MemoryMXBean`的实例可以通过`ManagementFactory.getMemoryMXBean()`获得。这个接口包含`...

    java获取计算机硬件基本信息

    Java的`com.sun.management.OperatingSystemMXBean`类提供了一些方法来获取系统内存和Java堆内存的信息。例如,以下代码可以显示系统总内存和可用内存: ```java import com.sun.management.OperatingSystemMXBean;...

    Java界面版 内存地址转换的三种方式过程演示

    例如,栈上分配策略将短生命周期的对象直接在虚拟机栈帧中分配,避免了堆内存的分配和回收。对象内存布局则涉及到实例字段、对齐填充等,JVM会根据这些信息计算出对象的实际内存地址。 在“Java界面版 内存地址转换...

    获取内存某地址基本信息

    在更高级别的语言如Java或.NET中,虽然程序员通常不直接处理内存地址,但仍有工具(如Java的JVisualVM或.NET的CLR Profiler)可以帮助获取对象在内存中的位置和其他相关信息。 标签“内存”表明主题聚焦于内存管理...

    java解决大批量数据导出Excel产生内存溢出的方案

    可以通过增加`-Xms`和`-Xmx`参数来设置初始和最大堆内存,但这种方法只是治标不治本,对于大规模数据导出,更推荐使用上述流式处理方案。 5. **延迟计算和写入**: - 只在需要时才计算和写入数据,而不是预先计算...

    Java内存监视器.rar

    Java内存模型主要分为三个区域:堆内存(Heap)、栈内存(Stack)和方法区(Method Area),在Java 8及以后版本,还包含了元空间(Metaspace)。每个区域都有其特定的用途: 1. **堆内存**:存储所有对象实例和数组...

    java 对象 内存 大小

    Java对象主要存储在堆内存中,堆是由JVM管理的动态内存区域,用于存放类实例和数组。每个Java对象都包含两部分:对象头和实例数据。 1. **对象头**: - **Mark Word**:包含对象的哈希码、锁状态标志、GC分代年龄...

    JAVA内存分析 - V1.0.0.zip

    使用MAT进行内存分析时,首先需要获取heap dump文件,这可以通过在JVM启动时添加"-XX:+HeapDumpOnOutOfMemoryError"或手动触发的方式实现。然后,在MAT中导入这个dump文件,进行如下步骤的分析: 1. **概述报告**:...

    javamemory_JAVA内存监视器_java_

    Java的垃圾收集器(Garbage Collector, GC)主要负责堆内存的分配和回收。当对象不再被引用时,垃圾收集器会自动清理这些不再使用的内存,以防止内存泄漏。然而,过度的垃圾收集可能导致性能下降,因此监控堆内存的...

    android 7.1 获取各个应用的各种内存信息的app demo

    Android系统将内存分为多个层次,包括Dalvik/ART堆内存、Native堆内存、Ashmem分配的内存以及系统缓存等。每个应用程序都有自己的Dalvik/ART虚拟机实例,负责管理Java对象的内存。此外,Android还提供了用于C/C++...

    java IBM websphere 内存溢出 javacore deapdump CPU内存分析工具

    1. 堆内存:Java对象主要存储在堆内存中,过大或过多的对象可能导致堆溢出。 2. 非堆内存:包括JVM自身使用的内存(如方法区、元空间)和线程栈,这部分内存也可能导致溢出。 3. GC(Garbage Collection):Java的...

    Mac OS java内存分析工具MAT

    MAT是Eclipse项目的一部分,它是一款免费且开源的工具,专门用于分析Java堆转储(Heap Dump)文件,帮助开发者识别内存泄漏、分析内存占用情况以及优化内存使用。MAT提供了丰富的功能和视图,使得复杂的内存问题变得...

    java 虚拟机 内存和栈 分析工具 ha456.rar

    堆内存被分为新生代(Young Generation)、老年代(Tenured Generation)和永久代( Perm Generation 或者元空间 Meta-Space),用于垃圾收集和对象生命周期管理。 2. **栈**:每个线程都有自己的程序计数器和一个...

    Java运行内存分析

    JVM内存主要分为以下几个部分:栈内存(Stack)、堆内存(Heap)、方法区(Method Area)、运行时常量池(Runtime Constant Pool)以及直接内存等。下面详细介绍这些内存区域的用途以及它们是如何协同工作来支持Java...

    java 内存泄露分析流程

    Java内存主要分为堆内存(Heap)、栈内存(Stack)和方法区(Method Area)。堆内存存储所有对象实例,而栈内存负责存储线程局部变量。方法区则用于存储类信息、常量、静态变量等。内存泄露通常发生在堆内存中,...

    java获取CPU等信息.rar

    同样在`java.lang.management`包中,`MemoryMXBean`接口提供内存信息,如堆内存、非堆内存、eden区、survivor区等的使用情况。通过`ManagementFactory.getMemoryMXBean().getHeapMemoryUsage()`和`...

Global site tag (gtag.js) - Google Analytics