Java 如何在';它不在控制台中运行

Java 如何在';它不在控制台中运行,java,jvm,heap-dump,thread-dump,Java,Jvm,Heap Dump,Thread Dump,我有一个从控制台运行的Java应用程序,该控制台反过来执行另一个Java进程。我想获得该子进程的线程/堆转储 在Unix上,我可以执行kill-3,但在Windows AFAIK上,获得线程转储的唯一方法是控制台中的Ctrl-Break。但这只给出了父进程的转储,而不是子进程的转储 还有其他方法获得堆转储吗?您可以从Cygwin发送kill-3。您必须使用Cygwinps选项查找windows进程,然后将信号发送到该进程。您必须将第二个java可执行文件的输出重定向到某个文件。 然后,使用连接到

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

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


还有其他方法获得堆转储吗?

您可以从Cygwin发送
kill-3
。您必须使用Cygwin
ps
选项查找windows进程,然后将信号发送到该进程。

您必须将第二个java可执行文件的输出重定向到某个文件。
然后,使用连接到第二个进程。

您可以运行
jconsole
(包含在Java 6的SDK中),然后连接到Java应用程序。它将显示运行的每个线程及其堆栈跟踪。

我建议使用JDK(jvisualvm.exe)分发的Java VisualVM。它可以动态连接并访问线程和堆。我发现了一些非常有用的问题。

除了使用前面提到的jconsole/visualvm之外,您还可以在另一个命令行窗口上使用
jstack-l
,并捕获该输出

可以使用任务管理器(它是windows和unix上的进程id)或使用
jps
找到


sunjdkversion6及更高版本中包含了
jstack
jps

您可以使用
jmap
获取任何正在运行的进程的转储,前提是您知道
pid

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

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

获取该进程的堆。

如果您想在内存不足的情况下启动heapdump,可以使用选项
-XX:-HeapDumpOnOutOfMemoryError


c、 f.

您混淆了两个不同的java转储
kill-3
生成线程转储,而不是堆转储

Thread dump=JVM输出到标准输出的每个线程的堆栈跟踪作为文本

Heap dump=JVM进程输出到二进制文件的内存内容

要在Windows上进行线程转储,如果JVM是前台进程,则CTRL+BREAK是最简单的方法。如果您在诸如Cygwin或MobaXterm之类的Windows上有一个类似unix的shell,那么您可以像在unix中一样使用
kill-3{pid}

要在Unix中进行线程转储,如果JVM是前台进程,则CTRL+C或
kill-3{pid}
可以工作,只要JVM的pid正确

对于这两种平台,Java都附带了一些实用程序,可以提供帮助。对于线程转储,
jstack{pid}
是最好的选择

只想结束转储问题:堆转储不常用,因为它们很难解释。但是,如果你知道在哪里/如何查看它们,它们里面有很多有用的信息。最常见的用法是查找内存泄漏。在java命令行上设置
-D
,以便在OutOfMemoryError时自动生成堆转储,
-XX:+HeapDumpOnAutofMemoryError
,但也可以手动触发堆转储。最常见的方法是使用java实用工具
jmap

注意:此实用程序并非在所有平台上都可用。从JDK1.6开始,
jmap
在Windows上可用

示例命令行如下所示

jmap -dump:file=myheap.bin {pid of the JVM}

输出“myheap.bin”不是人类可读的(对我们大多数人来说),您需要一个工具来分析它。我喜欢垫子

我认为在Linux进程中创建.hprof文件的最佳方法是使用jmap命令。例如:
jmap-dump:format=b,file=filename.hprof{PID}

如果您使用的是JDK1.6或更高版本,您可以使用
jmap
命令对Java进程进行堆转储,条件是您应该知道ProcessID

如果您在Windows计算机上,则可以使用任务管理器获取PID。对于Linux机器,您可以使用各种命令,如
ps-A | grep java
netstat-tupln | grep java
top | grep java
,具体取决于您的应用程序

然后可以使用类似于
jmap-dump:format=b,file=sample\u heap\u dump.hprof 1234的命令,其中1234是PID


有多种方法可以解释hprof文件。我将推荐Oracle的visualvm工具,它使用简单

如果您使用的是服务器jre 8及以上版本,则可以使用:

jcmd PID GC.heap_dump /tmp/dump

尝试以下选项之一

  • 对于32位JVM:

    jmap -dump:format=b,file=<heap_dump_filename> <pid>
    
    jmap-dump:format=b,file=
    
  • 对于64位JVM(显式引用):

    jmap-J-d64-dump:format=b,file=
    
  • 对于VM参数中使用G1GC算法的64位JVM(使用G1GC算法仅生成活动对象堆):

    jmap-J-d64-dump:live,格式=b,文件=
    
  • 相关问题:


    查看
    jmap
    的各种选项在此

    下面的脚本使用PsExec连接到另一个Windows会话,因此即使通过远程桌面服务连接,它也可以工作

    我为Java8编写了一个名为的小批量脚本(使用and
    jcmd
    ),它转储线程、堆、系统属性和JVM参数

    :: set the paths for your environment
    set PsExec=C:\Apps\SysInternals\PsExec.exe
    set JAVA_HOME=C:\Apps\Java\jdk1.8.0_121
    set DUMP_DIR=C:\temp
    
    @echo off
    
    set PID=%1
    
    if "%PID%"=="" (
        echo usage: jvmdump.bat {pid}
        exit /b
    )
    
    for /f "tokens=2,3,4 delims=/ " %%f in ('date /t') do set timestamp_d=%%h%%g%%f
    for /f "tokens=1,2 delims=: " %%f in ('time /t') do set timestamp_t=%%f%%g
    set timestamp=%timestamp_d%%timestamp_t%
    echo datetime is: %timestamp%
    
    echo ### Version >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    %PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.version >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    
    echo. >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    echo ### Uptime >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    %PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.uptime >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    
    echo. >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    echo ### Command >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    %PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.command_line >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    
    echo. >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    echo ### Flags >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    %PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.flags >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    
    echo. >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    echo ### Properties >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    %PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.system_properties >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    
    %PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% Thread.print -l >"%DUMP_DIR%\%PID%-%timestamp%-threads.log"
    
    %PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% GC.heap_dump "%DUMP_DIR%\%PID%-%timestamp%-heap.hprof"
    
    echo Dumped to %DUMP_DIR%
    
    它必须在启动JVM的用户的同一个Windows会话中运行,因此,如果您通过远程桌面连接,则可能需要在会话0中启动命令提示符,然后从那里运行它。e、 g

    %PsExec% -s -h -d -i 0 cmd.exe
    

    这将提示您(单击底部的任务栏图标)在交互式会话中查看消息,该消息将在另一个会话中带您到新控制台,您可以从中运行
    jvmdump.bat
    脚本。

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

    <
    :: set the paths for your environment
    set PsExec=C:\Apps\SysInternals\PsExec.exe
    set JAVA_HOME=C:\Apps\Java\jdk1.8.0_121
    set DUMP_DIR=C:\temp
    
    @echo off
    
    set PID=%1
    
    if "%PID%"=="" (
        echo usage: jvmdump.bat {pid}
        exit /b
    )
    
    for /f "tokens=2,3,4 delims=/ " %%f in ('date /t') do set timestamp_d=%%h%%g%%f
    for /f "tokens=1,2 delims=: " %%f in ('time /t') do set timestamp_t=%%f%%g
    set timestamp=%timestamp_d%%timestamp_t%
    echo datetime is: %timestamp%
    
    echo ### Version >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    %PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.version >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    
    echo. >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    echo ### Uptime >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    %PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.uptime >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    
    echo. >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    echo ### Command >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    %PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.command_line >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    
    echo. >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    echo ### Flags >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    %PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.flags >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    
    echo. >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    echo ### Properties >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    %PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% VM.system_properties >>"%DUMP_DIR%\%PID%-%timestamp%-jvm.log"
    
    %PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% Thread.print -l >"%DUMP_DIR%\%PID%-%timestamp%-threads.log"
    
    %PsExec% -s %JAVA_HOME%\bin\jcmd.exe %PID% GC.heap_dump "%DUMP_DIR%\%PID%-%timestamp%-heap.hprof"
    
    echo Dumped to %DUMP_DIR%
    
    %PsExec% -s -h -d -i 0 cmd.exe
    
    private static String getThreadDump() {
        Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();
    
        StringBuilder out = new StringBuilder();
        for (Map.Entry<Thread, StackTraceElement[]> entry : allStackTraces.entrySet()) {
            Thread thread = entry.getKey();
            StackTraceElement[] elements = entry.getValue();
            out.append(String.format("%s | prio=%d | %s", thread.getName(), thread.getPriority(), thread.getState()));
            out.append('\n');
    
            for (StackTraceElement element : elements) {
                out.append(element.toString()).append('\n');
            }
            out.append('\n');
        }
        return out.toString();
    }
    
    main | prio=5 | RUNNABLE
    java.lang.Thread.dumpThreads(Native Method)
    java.lang.Thread.getAllStackTraces(Thread.java:1607)
    Main.getThreadDump(Main.java:8)
    Main.main(Main.java:36)
    
    Monitor Ctrl-Break | prio=5 | RUNNABLE
    java.net.PlainSocketImpl.initProto(Native Method)
    java.net.PlainSocketImpl.<clinit>(PlainSocketImpl.java:45)
    java.net.Socket.setImpl(Socket.java:503)
    java.net.Socket.<init>(Socket.java:424)
    java.net.Socket.<init>(Socket.java:211)
    com.intellij.rt.execution.application.AppMainV2$1.run(AppMainV2.java:59)
    
    Finalizer | prio=8 | WAITING
    java.lang.Object.wait(Native Method)
    java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:143)
    java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
    java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)
    
    Reference Handler | prio=10 | WAITING
    java.lang.Object.wait(Native Method)
    java.lang.Object.wait(Object.java:502)
    java.lang.ref.Reference.tryHandlePending(Reference.java:191)
    java.lang.ref.Reference$ReferenceHandler.run(Reference.java:153)
    
    private static String getThreadDump() {
        Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();
        StringBuilder out = new StringBuilder();
        allStackTraces.forEach((thread, elements) -> {
            out.append(String.format("%s | prio=%d | %s", thread.getName(), thread.getPriority(), thread.getState()));
            out.append('\n');
    
            Arrays.stream(elements).forEach(element -> out.append(element.toString()).append('\n'));
            out.append('\n');
        });
        return out.toString();
    }
    
    System.out.print(getThreadDump());
    
    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;
    }