我有一个从控制台运行的Java应用程序,该应用程序反过来执行另一个Java进程。我想获得该子进程的线程/堆转储。
在Unix上,我可以执行kill -3 <pid>,但在Windows AFAIK上,获得线程转储的唯一方法是在控制台中按Ctrl-Break。但这只给了我父进程的转储,而不是子进程的转储。
有其他方法来获取堆转储吗?
我有一个从控制台运行的Java应用程序,该应用程序反过来执行另一个Java进程。我想获得该子进程的线程/堆转储。
在Unix上,我可以执行kill -3 <pid>,但在Windows AFAIK上,获得线程转储的唯一方法是在控制台中按Ctrl-Break。但这只给了我父进程的转储,而不是子进程的转储。
有其他方法来获取堆转储吗?
当前回答
下面的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)
也许jcmd ?
Jcmd实用程序用于向JVM发送诊断命令请求,这些请求对于控制Java Flight records、故障排除以及诊断JVM和Java应用程序非常有用。
The jcmd tool was introduced with Oracle's Java 7 and is particularly useful in troubleshooting issues with JVM applications by using it to identify Java processes' IDs (akin to jps), acquiring heap dumps (akin to jmap), acquiring thread dumps (akin to jstack), viewing virtual machine characteristics such as system properties and command-line flags (akin to jinfo), and acquiring garbage collection statistics (akin to jstat). The jcmd tool has been called "a swiss-army knife for investigating and resolving issues with your JVM application" and a "hidden gem."
下面是调用jcmd时需要使用的过程:
进入jcmd <pid> GC。heap_dump <文件路径> 在这 pid: Java进程Id,将为其捕获堆转储 file-path:打印堆转储的文件路径。
有关获取Java堆转储的更多信息,请参阅本文。
除了使用上面提到的jconsole/visualvm之外,您还可以在另一个命令行窗口上使用jstack -l <vm-id>,并捕获输出。
<vm-id>可以使用任务管理器(它是windows和unix上的进程id)或使用jps找到。
jstack和jps都包含在Sun JDK版本6及更高版本中。
我推荐JDK附带的Java VisualVM (jvisualvm.exe)。它可以动态连接并访问线程和堆。我发现在某些问题上它是无价的。
如果你想在内存不足时进行堆转储,你可以使用-XX:-HeapDumpOnOutOfMemoryError选项启动Java
c.f. JVM选项参考页