我有一个从控制台运行的Java应用程序,该应用程序反过来执行另一个Java进程。我想获得该子进程的线程/堆转储。

在Unix上,我可以执行kill -3 <pid>,但在Windows AFAIK上,获得线程转储的唯一方法是在控制台中按Ctrl-Break。但这只给了我父进程的转储,而不是子进程的转储。

有其他方法来获取堆转储吗?


当前回答

我推荐JDK附带的Java VisualVM (jvisualvm.exe)。它可以动态连接并访问线程和堆。我发现在某些问题上它是无价的。

其他回答

如何获取java应用程序的进程id ?

执行“jcmd”命令可获取java应用程序的进程id。

如何获得线程转储?

jcmd PID线程。打印>线程

参考链接

您甚至可以使用jstack来获取线程转储(jstack PID > thread.dump)。参考链接

如何获得堆转储?

使用jmap工具获取堆转储。 jmap -F -dump:live,format=b,file=heap.bin PID

PID:应用程序的进程号。参考链接

在Oracle JDK中,我们有一个名为jmap的命令(在Java Home的bin文件夹中可用)。 该命令的用法如下

Jmap (option) (pid)

示例:jmap -dump:live,format=b,file=heap.bin (pid)

为了从windows中的子java进程中获取线程转储/堆转储,首先需要确定子进程Id。

通过发出命令:jps,您将能够获得在您的windows计算机上运行的所有java进程id。您需要从该列表中选择子进程Id。一旦有了子进程Id,就可以使用各种选项来捕获线程转储和堆转储。

捕获线程转储:

有8个选项来捕获线程转储:

jstack 杀了3 jvisualVM 江铃汽车 Windows (Ctrl + Break) ThreadMXBean APM的工具 jcmd

关于每个选项的详细信息可以在本文中找到。有了捕获线程转储之后,可以使用fastThread、samurai等工具来分析线程转储。

捕获堆转储:

有7个选项可以捕获堆转储:

jmap - xx: + HeapDumpOnOutOfMemoryError jcmd JVisualVM JMX 编程方法 管理控制台

关于每个选项的详细信息可以在本文中找到。捕获堆转储之后,可以使用Eclipse内存分析工具HeapHero等工具来分析捕获的堆转储。

下面的java代码通过提供一个远程进程的PID来获取java进程的堆转储。该程序使用远程JMX连接转储堆到一个文件。它可能对某人有帮助。不需要jmap。

import java.lang.management.ManagementFactory;
import javax.management.MBeanServerConnection;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.lang.reflect.Method;

public class HeapDumper {

public static final String HOST = "192.168.11.177";
public static final String PORT = "1600";
public static final String FILE_NAME = "heapDump.hprof";
public static final String FOLDER_PATH = "C:/";
private static final String HOTSPOT_BEAN_NAME ="com.sun.management:type=HotSpotDiagnostic";

public static void main(String[] args) {
    if(args.length == 0) {
        System.out.println("Enter PID of the Java Process !!!");
        return;
    }
    
    String pidString = args[0];
    int pid = -1;
    if(pidString!=null && pidString.length() > 0) {
        try {
            pid = Integer.parseInt(pidString);
        }
        catch(Exception e) {
            System.out.println("PID is not Valid !!!");
            return;
        }
    }
    boolean isHeapDumpSuccess = false;
    boolean live = true;
    if(pid > 0) {
        MBeanServerConnection beanServerConn = getJMXConnection();
        
        if(beanServerConn!=null) {
            Class clazz = null;
            String dumpFile = FOLDER_PATH+"/"+FILE_NAME;
            try{
                clazz = Class.forName("com.sun.management.HotSpotDiagnosticMXBean");
                Object hotspotMBean = ManagementFactory.newPlatformMXBeanProxy(beanServerConn, HOTSPOT_BEAN_NAME, clazz);
                Method method = clazz.getMethod("dumpHeap", new Class[]{String.class , boolean.class});
                method.setAccessible(true);
                method.invoke(hotspotMBean , new Object[] {dumpFile, new Boolean(live)});
                isHeapDumpSuccess = true;
            }
            catch(Exception e){
                e.printStackTrace();
                isHeapDumpSuccess = false;
            }
            finally{
                clazz = null;
            }
        }
    }
    
    if(isHeapDumpSuccess){
        System.out.println("HeapDump is Success !!!");
    }
    else{
        System.out.println("HeapDump is not Success !!!");
    }
}

private static MBeanServerConnection getJMXConnection() {
    MBeanServerConnection mbeanServerConnection = null;
    String urlString = "service:jmx:rmi:///jndi/rmi://" + HOST + ":" + PORT + "/jmxrmi";
    try {
        JMXServiceURL url = new JMXServiceURL(urlString);
        JMXConnector jmxConnector = JMXConnectorFactory.connect(url);
        mbeanServerConnection = jmxConnector.getMBeanServerConnection();
        System.out.println("JMX Connection is Success for the URL :"+urlString);
    }
    catch(Exception e) {
        System.out.println("JMX Connection Failed !!!");
    }
    return mbeanServerConnection;
}

}

您可以使用jmap获取正在运行的任何进程的转储,假设您知道pid。

使用任务管理器或资源监视器获取pid。然后

jmap -dump:format=b,file=heap.hprof <pid>

获取该进程的堆。

对于安装了bash和pgrep并且正在运行单个Java进程的系统,请尝试:

jmap -dump:format=b,file=heap.hprof $(pgrep java)