在应用程序内部创建堆转储文件,不使用HotSpotDiagnosticMXBean

17

如何在应用程序内部创建堆转储文件,而不使用HotSpotDiagnosticMXBean类。由于无法访问java/rt.jar,我无法将其编译为依赖项HotSpotDiagnosticMXBean。我知道如何解决eclipse.compiler错误,但是我该如何解决构建问题?是否有其他方法可以通过编程方式创建堆转储?


你看过这个吗:http://java.sun.com/developer/technicalArticles/J2SE/monitoring/? - Dmitry Zagorulkin
1
你能不能解除访问限制,这样你就可以按照规定的方式操作了?要么你需要这样做并且有权限,要么你没有权限,那么你就不应该尝试。 - Peter Lawrey
@Peter Lawrey 我无法解除限制(也许有编译器选项?)第二个选择是以其他方式触发堆转储。 - Chriss
5个回答

23

好的,看起来你可以通过使用反射绕过限制:

package lab.heapdump;

import javax.management.MBeanServer;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Method;


@SuppressWarnings("restriction")
public class HeapDump {
    // This is the name of the HotSpot Diagnostic MBean
    private static final String HOTSPOT_BEAN_NAME =
         "com.sun.management:type=HotSpotDiagnostic";

    // field to store the hotspot diagnostic MBean 
    private static volatile Object hotspotMBean;

    /**
     * Call this method from your application whenever you 
     * want to dump the heap snapshot into a file.
     *
     * @param fileName name of the heap dump file
     * @param live flag that tells whether to dump
     *             only the live objects
     */
    static void dumpHeap(String fileName, boolean live) {
        // initialize hotspot diagnostic MBean
        initHotspotMBean();
        try {
            Class clazz = Class.forName("com.sun.management.HotSpotDiagnosticMXBean");
            Method m = clazz.getMethod("dumpHeap", String.class, boolean.class);
            m.invoke( hotspotMBean , fileName, live);
        } catch (RuntimeException re) {
            throw re;
        } catch (Exception exp) {
            throw new RuntimeException(exp);
        }
    }

    // initialize the hotspot diagnostic MBean field
    private static void initHotspotMBean() {
        if (hotspotMBean == null) {
            synchronized (HeapDump.class) {
                if (hotspotMBean == null) {
                    hotspotMBean = getHotspotMBean();
                }
            }
        }
    }

    // get the hotspot diagnostic MBean from the
    // platform MBean server
    private static Object getHotspotMBean() {
        try {
            Class clazz = Class.forName("com.sun.management.HotSpotDiagnosticMXBean");
            MBeanServer server = ManagementFactory.getPlatformMBeanServer();
            Object bean = 
                ManagementFactory.newPlatformMXBeanProxy(server,
                HOTSPOT_BEAN_NAME, clazz);
            return bean;
        } catch (RuntimeException re) {
            throw re;
        } catch (Exception exp) {
            throw new RuntimeException(exp);
        }
    }

    public static void main(String[] args) {
        // default heap dump file name
        String fileName = "D:\\heap.bin";
        // by default dump only the live objects
        boolean live = true;

        // simple command line options
        switch (args.length) {
            case 2:
                live = args[1].equals("true");
            case 1:
                fileName = args[0];
        }

        // dump the heap
        dumpHeap(fileName, live);
    }
}

反射很好用!只需要检查当前 JDK 中是否可用 HotSpotDiagnosticMXBean 类即可。 - Chriss
2
似乎是从https://blogs.oracle.com/sundararajan/entry/programmatically_dumping_heap_from_java进行了适应。 - Thorbjørn Ravn Andersen
你确定这个会起作用吗?如果我写成这样:getMethod("dumpHeap", String.class, boolean.class) .. 我会得到错误信息 "not applicable for arguments String, Class<T>, Class<T>" ... 所以我必须使用数组:new Class[] {String.class, boolean.class} 作为第二个参数,并且调用的方式是这样的:m.invoke(hotspotMBean, new Object[] {fileName, Boolean.valueOf(live)}); - Racky

6
package ru.test;

import com.sun.management.HotSpotDiagnosticMXBean;
import org.junit.Test;

import java.io.IOException;
import java.lang.management.ManagementFactory;

public class TestDump {
    @Test
    public void test() throws IOException {
        long i = 6789;
        String s = "HELLO";
        System.out.println(i);
        System.out.println(s);

        HotSpotDiagnosticMXBean mxBean = ManagementFactory.newPlatformMXBeanProxy(ManagementFactory.getPlatformMBeanServer(),
                "com.sun.management:type=HotSpotDiagnostic", HotSpotDiagnosticMXBean.class);
        mxBean.dumpHeap("C:\\temp\\dump\\heap1.bin", true);
    }
}

输出:

6789
HELLO    


Process finished with exit code 0

0

你可以复制包含HotSpotDiagnosticMXBean.class的rt.jar文件到另一个位置。使用"添加外部jar"在构建路径中引用复制的jar文件。 这样就可以创建对象并获取堆转储。

new HotSpotDiagnostic().dumpHeap("d:\\HeapDump1",true);

我能够通过这种方式生成Heapdump。 我正在寻找任何运行时冲突的JAR错误。 幸运的是没有。

-1

VisualVM可以生成堆转储。

您还可以在Linux系统上尝试jhat命令。


2
我知道,但是我想在我的应用程序内部触发一个堆转储,而不需要外部程序的帮助。 - Chriss

-1

这个类是公共的,所以你可能无法访问它的唯一原因是你的JVM版本太旧了。

链接的示例在Java 6和7中编译和运行良好。如果可能的话,请尝试升级到最新版本的Java。


2
我正在使用Java7。问题在于HotSpotDiagnosticMXBean不是公共的HotSpotDiagnosticMXBean类(它不是JDK的一部分)。这个类只存在于Oracle Java发行版中,它是依赖于JVM的。 - Chriss
1
这意味着该功能依赖于JVM,您可以编译代码,但在不支持此功能的JVM上可能无法运行。您使用哪些JVM版本? - Peter Lawrey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接