콘솔에서 실행되지 않는 Windows에서 Java 프로세스의 스레드 및 힙 덤프를 얻는 방법


232

콘솔에서 실행하는 Java 응용 프로그램이 있으며 다른 Java 프로세스를 실행합니다. 해당 자식 프로세스의 스레드 / 힙 덤프를 가져오고 싶습니다.

유닉스에서는 할 수 kill -3 <pid>있지만 Windows AFAIK에서는 스레드 덤프를 얻는 유일한 방법은 콘솔의 Ctrl-Break입니다. 그러나 그것은 저에게 부모 프로세스의 덤프를 제공하지만 자식은 아닙니다.

해당 힙 덤프를 얻는 다른 방법이 있습니까?


답변:


376

jmap을 알고 있다고 가정하면 실행중인 프로세스의 덤프를 얻는 데 사용할 수 있습니다 pid.

작업 관리자 또는 리소스 모니터를 사용하여 pid. 그때

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

해당 프로세스의 힙을 가져옵니다.


Windows에서 JDK5에 jmap을 사용할 수 없습니다. Windows에서 JDK5로 덤프 할 수있는 방법이 있습니까?
Santron Manibharathi

173
이 쓰레드는 너무 인기가 높아서 누군가가 힙 덤프를 "cheap.bin"이라고 언급 한 것을 들었습니다.
mjaggard

7
보다 간단한 파일 이름 : "heap.hprof"(HPROF 형식)
MGM

1
Java 프로세스를 시작한 올바른 사용자를 사용해야합니다. 내 경우에는 tomcat8 ps -C java -o pid sudo -u tomcat8 jmap -dump : format = b, file = <filename> <pid>
bitsabhi

115

두 개의 다른 Java 덤프를 혼동하고 있습니다. kill -3힙 덤프가 아닌 스레드 덤프를 생성합니다.

스레드 덤프 = JVM 출력의 각 스레드에 대한 스택 추적으로 텍스트로 stdout합니다.

힙 덤프 = JVM 프로세스의 메모리 내용이 2 진 파일로 출력됩니다.

Windows에서 스레드 덤프를 수행하려면 JVM이 포 그라운드 프로세스 인 경우 CTRL+ BREAK가 가장 간단한 방법입니다. Cygwin 또는 MobaXterm과 같은 Windows kill -3 {pid}에 유닉스 계열 쉘이 있으면 Unix에서와 같이 사용할 수 있습니다.

Unix에서 스레드 덤프를 가져 오려면 JVM이 포 그라운드 프로세스이거나 JVM에 대한 올바른 PID를 얻는 한 작동 하는 경우 CTRL+ .Ckill -3 {pid}

두 플랫폼 중 하나에 Java에는 도움이되는 여러 유틸리티가 제공됩니다. 스레드 덤프의 경우 jstack {pid}가장 좋은 방법입니다. http://docs.oracle.com/javase/1.5.0/docs/tooldocs/share/jstack.html

덤프 문제를 해결하는 것 : 힙 덤프는 해석하기 어렵 기 때문에 일반적으로 사용되지 않습니다. 그러나 어디에서 어떻게 볼 것인지 알고 있다면 유용한 정보가 많이 있습니다. 가장 일반적인 사용법은 메모리 누수를 찾는 것입니다. -DOutOfMemoryError시 힙 덤프가 자동으로 생성되도록 java 명령 행 에서 on 을 설정하는 것이 좋지만 -XX:+HeapDumpOnOutOfMemoryError 수동으로 힙 덤프를 트리거 할 수도 있습니다. 가장 일반적인 방법은 java 유틸리티를 사용하는 것 jmap입니다.

참고 : 이 유틸리티는 모든 플랫폼에서 사용 가능한 것은 아닙니다. JDK 1.6부터 jmapWindows에서 사용할 수 있습니다.

예제 명령 줄은 다음과 같습니다.

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

출력 "myheap.bin"은 사람이 읽을 수 없으며 (대부분의 사람들에게) 분석 할 도구가 필요합니다. 선호하는 것은 매트입니다. http://www.eclipse.org/mat/


3
내 리눅스 Ctrl-C에서 인터럽트를 종료 (종료)합니다. Ctrl- \
nafg

고려 "Windows에서 스레드 덤프, CTRL + BREAK을 촬영하려면"과에 미치는 일반적인 영향을. 실제로 제조업체의 엔지니어링 결정에 달려 있습니다. FE, IIRC 인 Lenova는 cntrl + fn + p이다.
ChiefTwoPencils

30

Linux 프로세스에서 .hprof 파일을 만드는 가장 좋은 방법은 jmap 명령을 사용하는 것입니다. 예를 들면 다음과 같습니다.jmap -dump:format=b,file=filename.hprof {PID}


19

언급 된 jconsole / visualvm을 사용하는 것 외에도 jstack -l <vm-id>다른 명령 행 창에서 사용하여 해당 출력을 캡처 할 수 있습니다 .

<vm-id>는 작업 관리자 (Windows 및 UNIX의 프로세스 ID) 또는을 사용하여 찾을 수 jps있습니다.

둘 다 jstack하고 jps있는 일 JDK 버전 6 이상에 포함되어 있습니다.


이 도구는 Java 1.6에서 지원되지 않습니다. Java 1.6에는 jconsole 만 있습니다.
Vanchinathan Chandrasekaran

7
JDK와 JRE를 혼합했을 수도 있습니다. JDK를 명시 적으로 언급했습니다. 다음 도구에 대한 설명서를 참조하십시오 : download.oracle.com/javase/6/docs/technotes/tools/share/…download.oracle.com/javase/6/docs/technotes/tools/share/…
ankon

17

JDK (jvisualvm.exe)와 함께 배포 된 Java VisualVM을 권장합니다. 동적으로 연결하고 스레드와 힙에 액세스 할 수 있습니다. 나는 몇 가지 문제에 대해 귀중한 것을 발견했습니다.


2
그것은 오버 헤드가 부착되어 있고 스레드 덤프는 일반적으로 생산 기계에서 검색되므로 실행 불가능합니다.
Hammad Dar

원래 질문은 '비 실행'프로세스에 관한 것입니다. jvisualvm이 연결되지 않을 수 있습니다.
Jaberino

3
@Jaberino : 아니요, Windows에서 현재 실행중인 Java 프로세스와 관련하여 콘솔이 없습니다.
Lawrence Dol

최신 Java 릴리스에서는 Java VisualVM이 JMC / JFR 로 대체되었습니다 . JVisualVM과 Java Mission Control의 차이점은 무엇입니까?를
Vadzim 2019 년

16

server-jre 8 이상인 경우 다음을 사용할 수 있습니다.

jcmd PID GC.heap_dump /tmp/dump

1
대부분의 프로덕션 시스템에는 jdk가 아닌 jre 만 있습니다. 도움이됩니다.
Pragalathan M

15

아래 옵션 중 하나를 시도하십시오.

  1. 32 비트 JVM의 경우 :

    jmap -dump:format=b,file=<heap_dump_filename> <pid>
  2. 64 비트 JVM (명시 인용)의 경우 :

    jmap -J-d64 -dump:format=b,file=<heap_dump_filename> <pid>
  3. VM 매개 변수에 G1GC 알고리즘이있는 64 비트 JVM의 경우 (G1GC 알고리즘으로 라이브 오브젝트 힙만 생성됨) :

    jmap -J-d64 -dump:live,format=b,file=<heap_dump_filename> <pid>

관련 SE 질문 : jmap 명령으로 Java 힙 덤프 오류 : 조기 EOF

jmap기사 에서 다양한 옵션을 살펴보십시오.


13

메모리 부족에서 힙 덤프를 원하면 옵션으로 Java를 시작할 수 있습니다. -XX:-HeapDumpOnOutOfMemoryError

cf JVM 옵션 참조 페이지


고마워 다니엘. 이 파일은 Windows 컴퓨터에서 어디에 생성됩니까? 기본 경로가 있습니까?
용암

1
@lava Oracle의 VM 옵션 페이지에 설명 된대로 -XX : HeapDumpPath를 통해 경로를 설정할 수 있습니다 .
kamczak

대박. 나는 메모리 누수를 보여주기 위해 밤새 테스트를 원했지만 내가없는 동안 OOM과 충돌이 걱정되었습니다. 이것은 완벽 해요.
바질

7

jconsole(Java 6 SDK에 포함 된) 실행 한 다음 Java 애플리케이션에 연결할 수 있습니다. 실행중인 모든 스레드와 스택 추적을 보여줍니다.


최고의 답변! 지금까지 이것을 알지 못했고 실제로 실용적입니다!
Xerus

7

kill -3 <pid>Cygwin에서 보낼 수 있습니다 . Cygwin ps옵션 을 사용하여 Windows 프로세스를 찾은 다음 해당 프로세스로 신호를 보내면됩니다.



3

JDK 1.6 이상을 사용하는 경우 jmap명령을 사용 하여 Java 프로세스의 힙 덤프를 사용할 수 있습니다 . 조건은 ProcessID를 알고 있어야합니다.

Windows 시스템에있는 경우 작업 관리자를 사용하여 PID를 얻을 수 있습니다. 리눅스 머신의 경우는 같은 명령의 종류를 사용 ps -A | grep java하거나 netstat -tupln | grep java또는 top | grep java, 응용 프로그램에 따라 다릅니다.

그런 다음 jmap -dump:format=b,file=sample_heap_dump.hprof 12341234가 PID 인 경우 와 같은 명령을 사용할 수 있습니다 .

hprof 파일을 해석하는 데 사용할 수 있는 다양한 도구가 있습니다 . 사용하기 쉬운 Oracle의 visualvm 도구를 추천합니다.


3

어떤 이유로 콘솔 / 터미널을 사용할 수 없거나 원하지 않는 경우 다른 해결책이 있습니다. Java 응용 프로그램이 스레드 덤프를 인쇄하도록 할 수 있습니다. 스택 추적을 수집하는 코드는 간단하며 버튼이나 웹 인터페이스에 연결할 수 있습니다.

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)

스트림이있는 Java 8 버전에 관심이있는 사용자는 코드가 훨씬 더 간결합니다.

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

3

다음 스크립트는 PsExec을 사용하여 다른 Windows 세션에 연결하므로 원격 데스크톱 서비스를 통해 연결된 경우에도 작동합니다.

스레드, 힙, 시스템 속성 및 JVM 인수를 덤프하는 Java 8 ( PsExec및 사용 jcmd)이라는 작은 배치 스크립트를 작성했습니다 jvmdump.bat.

:: 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 세션에서 실행해야하므로 원격 데스크탑을 통해 연결하는 경우 명령 프롬프트를 실행하여 실행해야합니다 Session 0. 예 :

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

View the message대화식 세션 에서 (작업 표시 줄 아이콘을 클릭하여) 대화식 세션으로 프롬프트하면 jvmdump.bat스크립트를 실행할 수있는 다른 세션의 새 콘솔로 이동합니다 .


2

Java 애플리케이션의 프로세스 ID를 얻는 방법은 무엇입니까?

'jcmd'명령을 실행하여 Java 애플리케이션의 프로세스 ID를 가져 오십시오.

스레드 덤프를 얻는 방법?

jcmd PID Thread.print> 스레드. 덤프

참조 링크

jstack을 사용하여 스레드 덤프를 얻을 수도 있습니다 (jstack PID> thread.dump). 참조 링크

힙 덤프를 얻는 방법?

jmap 도구를 사용하여 힙 덤프를 가져 오십시오. jmap -F-덤프 : 실시간, 형식 = b, 파일 = heap.bin PID

PID는 애플리케이션의 프로세스 ID를 나타냅니다. 참조 링크


1

아마도 jcmd ?

Jcmd 유틸리티는 진단 명령 요청을 JVM으로 전송하는 데 사용되며,이 요청은 Java Flight Recording을 제어하고 JVM 및 Java 응용 프로그램의 문제점을 해결하고 진단하는 데 유용합니다.

jcmd 도구는 Oracle의 Java 7에 도입되었으며 특히 Java 프로세스의 ID (aks에서 jps)를 식별하고 힙 덤프 (akin에서 jmap으로)를 획득하고 스레드 덤프를 가져 오기 (jstack으로)로 JVM 응용 프로그램의 문제점을 해결하는 데 특히 유용합니다. ), 시스템 속성 및 명령 줄 플래그 (akin to jinfo) 및 가비지 수집 통계 수집 (akin to jstat)과 같은 가상 시스템 특성보기 jcmd 도구는 "JVM 응용 프로그램의 문제를 조사하고 해결하기위한 스위스 군용 칼"과 "숨겨진 보석"이라고합니다.

다음을 호출 할 때 사용해야하는 프로세스는 다음과 같습니다 jcmd.

  1. 이동 jcmd <pid> GC.heap_dump <file-path>
  2. 어느
  3. pid : Java 프로세스 ID로 힙 덤프가 캡처됩니다.
  4. file-path : 힙 덤프가 인쇄되는 파일 경로입니다.

Java 힙 덤프 수행에 대한 자세한 정보는이를 확인하십시오 .


0

Visualvm 후속 조치 :

올바른 JVM 인수로 시작하지 않고 (원격 상자에 있음) jvisualvm에서 실행중인 JVM에 "연결할 수없는 경우"원격 상자에서 실행 jstatd한 다음 직접 연결되어 있다고 가정하면 visualvm에서 "원격 호스트"로 호스트 이름을 두 번 클릭하면 해당 상자의 다른 모든 JVM이 마술 적으로 visualvm에 표시됩니다.

해당 상자의 포트에 "직접 연결"하지 않은 경우 프록시를 통해이 작업을 수행 할 수도 있습니다 .

원하는 프로세스를 볼 수 있으면 jvisualvm에서 드릴하고 모니터 탭-> "힙 덤프"단추를 사용하십시오.


0

아래 자바 코드는 PID를 제공하여 Java 프로세스의 힙 덤프를 얻는 데 사용됩니다. 본 프로그램은 원격 JMX 연결을 사용하여 힙을 덤프합니다. 도움이 될 수도 있습니다.

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

}


0

Windows의 하위 Java 프로세스에서 스레드 덤프 / 힙 덤프를 가져 오려면 하위 프로세스 ID를 첫 번째 단계로 식별해야합니다.

jps 명령을 실행하면 Windows 시스템에서 실행중인 모든 Java 프로세스 ID를 얻을 수 있습니다. 이 목록에서 하위 프로세스 ID를 선택해야합니다. 하위 프로세스 ID가 있으면 스레드 덤프 및 힙 덤프를 캡처하는 다양한 옵션이 있습니다.

스레드 덤프 캡처 :

스레드 덤프를 캡처하는 8 가지 옵션이 있습니다.

  1. jstack
  2. 킬 -3
  3. jvisualVM
  4. JMC
  5. 윈도우 (Ctrl + Break)
  6. ThreadMXBean
  7. APM 도구
  8. jcmd

각 옵션에 대한 자세한 내용 은이 기사를 참조하십시오 . 캡처 스레드 덤프가 있으면 fastThread , Samuraito 와 같은 도구를 사용 하여 스레드 덤프를 분석 할 수 있습니다 .

힙 덤프 캡처 :

힙 덤프를 캡처하는 7 가지 옵션이 있습니다.

  1. jmap

  2. -XX : + HeapDumpOnOutOfMemoryError

  3. jcmd

  4. JVisualVM

  5. JMX

  6. 프로그래밍 방식

  7. 관리 콘솔

각 옵션에 대한 자세한 내용 은이 기사를 참조하십시오 . 힙 덤프를 캡처 한 후에는 Eclipse Memory Analysis tool , HeapHero 와 같은 도구 를 사용하여 캡처 된 힙 덤프를 분석 할 수 있습니다 .


-1

Oracle JDK에는 jmap이라는 명령이 있습니다 (Java Home의 bin 폴더에 있음). 명령 사용법은 다음과 같습니다.

jmap (옵션) (pid)

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.