programing

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

prostudy 2022. 4. 28. 20:35
반응형

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

나는 다른 Java 프로세스를 실행하는 콘솔에서 실행하는 Java 응용프로그램을 가지고 있다.나는 그 아동 과정의 실/치프 덤프를 받고 싶다.

유닉스에서는kill -3 <pid>Windows AFAIK에서 스레드 덤프를 가져오는 유일한 방법은 콘솔의 Ctrl-Break뿐이다.하지만 그건 내게 부모 과정의 쓰레기만 줄 뿐이지 아이가 아니야.

그 쓰레기 더미를 구할 다른 방법이 없을까?

사용할 수 있다jmap모든 공정을 처리한다는 걸 알고 있다고 가정할 때pid.

태스크 관리자 또는 리소스 모니터를 사용하여pid. 그러면.

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

그 과정을 위한 더미를 얻기 위해서.

다음 위치에 있는 시스템의 경우bash, 그리고pgrep설치되고 단일 Java 프로세스가 실행 중인 경우 다음을 시도해 보십시오.

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

너는 두 개의 다른 자바 덤프를 혼란스럽게 하고 있다. kill -3힙 덤프가 아닌 스레드 덤프를 생성한다.

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

힙 덤프 = 이진 파일에 대한 JVM 프로세스 출력에 대한 메모리 내용.

Windows에서 스레드 덤프를 사용하려면 BREAK+ JVM이 포그라운드 프로세스인 경우 가장 간단한 방법을 사용하십시오.만약 당신이 Cygwin이나 MobaXterm과 같은 윈도우에 유닉스 같은 셸을 가지고 있다면, 당신은 사용할 수 있다.kill -3 {pid}유닉스에서 할 수 있는 것처럼 말이야

Unix에서 스레드 덤프를 가져오려면 C+ JVM이 포그라운드 프로세스인 경우 또는kill -3 {pid}JVM에 적합한 PID를 얻는 한 효과가 있을 것이다.

어느 플랫폼이든 Java는 도움이 될 수 있는 몇 가지 유틸리티를 제공한다.스레드 덤프의 경우,jstack {pid}최선의 선택이야http://docs.oracle.com/javase/1.5.0/docs/tooldocs/share/jstack.html

덤프문문문문::: 힙 덤프는 때문에 되지 않는다힙 덤프는 해석하기 어렵기 때문에 일반적으로 사용되지 않는다.그러나, 만약 당신이 그들을 어디서 어떻게 보아야 하는지 안다면, 그들은 많은 유용한 정보를 가지고 있다.가장 일반적인 용도는 메모리 누출을 찾아내는 것이다.세팅하는 것은 좋은 습관이다.-DOutOfMemoryError 시 힙 덤프가 자동으로 생성되도록 Java 명령줄에서,-XX:+HeapDumpOnOutOfMemoryError그러나 힙 덤프를 수동으로 트리거할 수도 있다.가장 일반적인 방법은 Java 유틸리티를 사용하는 것이다.jmap.

참고: 일부 플랫폼에서는 이 유틸리티를 사용할 수 없다.JDK 1.6 기준.jmapWindows(윈도우)에서 사용 가능

예를 들어, 명령줄은

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

출력물 "myheap.bin"은 (우리 대부분에게) 사람이 읽을 수 있는 것이 아니며, 당신은 그것을 분석할 도구가 필요할 것이다.좋아하는 과목은 MAT 입니다. http://www.eclipse.org/mat/

리눅스 프로세스에서 .hprof 파일을 만드는 가장 좋은 방법은 jmap 명령어라고 생각한다.예를 들면 다음과 같다.jmap -dump:format=b,file=filename.hprof {PID}

하는 것 언한 jconsole/visualvmiling askoido를 할 수 .jstack -l <vm-id>다른 명령줄 창에서 해당 출력을 캡처하십시오.

<vm-id>는 작업 관리자(윈도우즈 및 유닉스의 프로세스 ID)를 사용하거나 다음을 사용하여 찾을 수 있다.jps.

둘 다jstack, 그리고jpsSun JDK 버전 6 이상에 포함되어 있다.

JDK(jisualvm.exe)와 함께 배포된 Java VisualVM을 권장한다.그것은 동적으로 연결될 수 있고 쓰레드와 힙에 접근할 수 있다.나는 몇 가지 문제에 있어서 매우 귀중한 것을 발견했다.

서버 jre 8 이상일 경우 다음을 사용하십시오.

jcmd PID GC.heap_dump /tmp/dump

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

  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에.

메모리 부족에 힙 덤프를 사용하려면 옵션으로 Java를 시작하십시오.-XX:-HeapDumpOnOutOfMemoryError

c.f. JVM 옵션 참조 페이지

당신은 보낼 수 있다.kill -3 <pid>사이그윈 출신이다넌 싸이윈을 사용해야 해psWindows 프로세스를 찾은 다음 해당 프로세스에 신호를 보내는 옵션.

넌 도망칠 수 있어jconsole(Java 6의 SDK에 포함) 그런 다음 Java 애플리케이션에 연결하십시오.모든 스레드 실행과 스택 추적을 보여줄 것이다.

두 번째 자바 실행 파일에서 일부 파일로 출력을 리디렉션해야 한다.그런 다음 SendSignal을 사용하여 두 번째 프로세스로 "-3"을 전송하십시오.

Java 응용프로그램의 프로세스 ID를 가져오는 방법

Java 애플리케이션의 프로세스 ID를 얻으려면 'jcmd' 명령을 실행하십시오.

스레드 덤프 어떻게 가지?

jcmd PID 스레드.print > 스레드.dump

참조 링크

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

힙 덤프 어떻게 구하지?

jmap 도구를 사용하여 힙 덤프를 가져오십시오. jmap -F -dump:live,format=b,file=heap.bin PID

PID는 응용프로그램의 프로세스 ID를 의미한다.참조 링크

다음 스크립트는 PsExec을 사용하여 다른 Windows 세션에 연결하여 원격 데스크톱 서비스를 통해 연결되어도 작동하도록 한다.

Java 8에 대한 작은 배치 스크립트를 작성했다(사용 및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%

하면 JVMling에서 해야 할 수 Session 0거기서 실행해 봐

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

아래쪽의 작업 표시줄 아이콘을 클릭하라는 메시지가 표시됨View the message 그 , 을 실행할 수 있다.jvmdump.bat각본으로 쓰다

JDK 1.6 이상을 사용하고 있는 경우, 사용할 수jmap힙을 취하도록 명령 Java 프로세스의 덤프, 조건: 프로세스를 알아야 함아이디

윈도우즈 시스템에 있는 경우 작업 관리자를 사용하여 PID를 가져올 수 있다.리눅스 시스템의 경우 다음과 같은 다양한 명령을 사용할 수 있다.ps -A | grep java또는netstat -tupln | grep java또는top | grep java는 당신의 어플리케이션에 따라 달라진다.

그러면 명령어를 다음과 같이 사용할 수 있다.jmap -dump:format=b,file=sample_heap_dump.hprof 1234여기서 1234는 PID이다.

HProf 파일을 해석하는 데 사용할 수 있는 다양한 도구가 있다.사용이 간편한 오라클의 비주얼vm 툴을 추천하겠다.

어떤 이유로 콘솔/단말기를 사용할 수 없는 경우(또는 원하지 않는 경우) 다른 해결책이 있다.당신은 Java 응용프로그램이 당신을 위해 스레드 덤프를 인쇄하도록 할 수 있다.Stack Trace를 수집하는 코드는 합리적으로 간단하며 버튼이나 웹 인터페이스에 부착할 수 있다.

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

아마도 jcmd?

Jcmd 유틸리티는 JVM에 진단 명령 요청을 보내는 데 사용되며, Java 비행 기록 제어, 문제 해결, JVM 및 Java 애플리케이션 진단에 유용하다.

jcmd 도구는 Oracle의 Java 7과 함께 도입되었으며, Java 프로세스의 ID(jps로 acin), 힙 덤프(jmap으로 acin), 스레드 덤프(jstack으로 acin), 시스템 속성 및 명령줄 플래그와 같은 가상 시스템 특성을 보기 위해 이 도구를 사용하여 JVM 애플리케이션의 문제를 해결하는 데 특히 유용하다.(akin to jinfo) 및 가비지 수집 통계 수집(akin to jstat)jcmd 도구는 "JVM 애플리케이션의 문제를 조사하고 해결하기 위한 스위스 군용 칼"과 "숨겨진 보석"이라고 불려왔다.

다음 절차를 사용하여 다음 작업을 호출하십시오.jcmd:

  1. 에 가다jcmd <pid> GC.heap_dump <file-path>
  2. 어느 곳에서
  3. pid: 힙 덤프가 캡처될 Java 프로세스 ID. 또한
  4. 파일 경로: 힙 덤프가 인쇄되는 파일 경로.

Java 덤프를 가져오는 방법에 대한 자세한 내용은 이 문서를 참조하십시오.

윈도우의 어린이 자바 프로세스에서 스레드 덤프/히프 덤프를 가져오려면 첫 번째 단계로 어린이 프로세스 ID를 식별해야 한다.

jps 명령을 실행하면 윈도우 머신에서 실행 중인 모든 Java 프로세스 ID를 얻을 수 있다.이 목록에서 하위 프로세스 ID를 선택하십시오.하위 프로세스 ID를 가지면 스레드 덤프와 힙 덤프를 캡처할 수 있는 다양한 옵션이 있다.

스레드 덤프 캡처:

스레드 덤프를 캡처하는 8가지 옵션:

  1. jstack
  2. -3을 죽이다
  3. 지비주얼VM
  4. JMC
  5. Windows(Ctrl + Break)
  6. 스레드MXBean
  7. APM 도구
  8. jcmd

각 옵션에 대한 자세한 내용은 이 문서에서 확인할 수 있다.일단 캡처 스레드 덤프가 있으면, 당신은 빠른 도구와 같은 도구를 사용할 수 있다.스레드, 사무라이토는 스레드 덤프를 분석한다.

힙 덤프 캡처 중:

힙 덤프를 캡처하는 7가지 옵션:

  1. 지맵

  2. -XX:+HeapDumpOnOutOfMemoryError

  3. jcmd

  4. JVisualVM

  5. JMX

  6. 프로그래밍 방식

  7. 콘솔

각 옵션에 대한 자세한 내용은 이 문서에서 확인할 수 있다.힙 덤프를 캡처한 후에는 Eclipse Memory Analysis 도구HipHero와 같은 도구를 사용하여 캡처된 힙 덤프를 분석할 수 있다.

아래 자바 코드는 원격 프로세스의 PID를 제공하여 자바 프로세스의 힙 덤프를 가져오는 데 사용된다.프로그램은 파일에 힙을 덤프하기 위해 원격 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;
}

}

Visualvm 후속 조치:

올바른 JVM 인수로 시작하지 않아 jvisualvm에서 실행 중인 JVM에 "연결할 수 없는" 경우(그리고 원격 상자에 있음) 실행jstatd그런 다음 직접 연결이 있다고 가정하여 원격 상자에서 visualvm에서 "원격 호스트"로 추가하고 호스트 이름을 두 번 클릭하면 해당 상자의 다른 모든 JVM이 visualvm에 마법처럼 나타난다.

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

원하는 프로세스를 볼 수 있으면 jvisualvm으로 드릴로 천공한 후 모니터 탭 -> "heapdump" 버튼을 사용하십시오.

Oracle JDK에는 jmap이라는 명령어가 있다(Java Home의 bin 폴더에서 사용 가능).명령어의 사용은 다음과 같다.

jmap(옵션)(pid)

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

참조URL: https://stackoverflow.com/questions/407612/how-to-get-a-thread-and-heap-dump-of-a-java-process-on-windows-thats-not-runnin

반응형