Windows'da bir konsolda çalışmayan bir Java işleminin iş parçacığı ve yığın dökümü nasıl elde edilir


232

Ben de başka bir Java işlemi yürüten bir konsoldan çalıştırmak bir Java uygulaması var. Bu alt sürecin bir iş parçacığı / yığın dökümü almak istiyorum.

Unix'te yapabilirdim kill -3 <pid>ama Windows AFAIK'te bir iş parçacığı dökümü almanın tek yolu konsoldaki Ctrl-Break. Ama bu bana sadece ebeveyn sürecinin çöplüğünü veriyor, çocuğu değil.

Bu yığın dökümü almanın başka bir yolu var mı?


Yanıtlar:


376

Biliyorsunuz, jmapherhangi bir işlemin dökümünü almak için kullanabilirsiniz pid.

Almak için Görev Yöneticisi'ni veya Kaynak İzleyicisi'ni kullanın pid. Sonra

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

bu süreç için yığın elde etmek.


jmap, Windows'ta JDK5 için kullanılamaz. Windows'ta JDK5 ile dökümü almanın bir yolu var mı?
Santron Manibharathi

173
Bu konu o kadar popüler oldu ki, birisinin "cheap.bin" olarak bir yığın dökümünden bahsettiğini duydum
mjaggard

7
Daha basit bir dosya adı: "heap.hprof", HPROF biçiminde olduğu gibi.
MGM

1
Java işlemini başlatan doğru kullanıcıyı kullandığınızdan emin olun. Benim durumumda tomcat8 ps -C java -o pid sudo -u tomcat8 jmap -dump: format = b, dosya = <filename> <pid>
bitsabhi 19:18

115

İki farklı java dökümünü karıştırıyorsunuz. kill -3yığın dökümü değil, iplik dökümü oluşturur.

İş parçacığı dökümü = stdout'u metin olarak JVM çıktısındaki her iş parçacığı için yığın izleri.

Yığın dökümü = JVM işlemi çıktısı için ikili dosyaya bellek içeriği.

Windows'ta bir iş parçacığı dökümü almak için, CTRL+ BREAKJVM'niz ön plan ise en basit yöntemdir. Cygwin veya MobaXterm gibi Windows'ta unix benzeri bir kabuğunuz varsa, Unix'te olduğu gibi kullanabilirsiniz kill -3 {pid}.

Unix'te bir iş parçacığı dökümü almak için, CTRL+ CJVM ön plan işlemiyse veya kill -3 {pid}JVM için doğru PID'yi aldığınız sürece çalışırsa.

Her iki platformda da Java yardımcı olabilecek çeşitli yardımcı programlarla birlikte gelir. İplik dökümleri jstack {pid}için en iyi seçimdir. http://docs.oracle.com/javase/1.5.0/docs/tooldocs/share/jstack.html

Sadece dökümü sorusunu bitirmek için: Yığın dökümü yaygın olarak kullanılmaz çünkü yorumlanması zordur. Ancak, nerede / nasıl bakılacağını biliyorsanız, içinde çok yararlı bilgiler var. En yaygın kullanım alanı bellek sızıntılarını bulmaktır. -DJava komut satırında, OutOfMemoryError üzerine yığın dökümü otomatik olarak oluşturulacak şekilde ayarlamak iyi bir uygulamadır , -XX:+HeapDumpOnOutOfMemoryError ancak bir yığın dökümü de el ile tetiklenebilir. En yaygın yol java yardımcı programını kullanmaktırjmap .

NOT: Bu yardımcı program tüm platformlarda kullanılamaz. JDK 1.6'dan jmapitibaren Windows'ta bulunmaktadır.

Örnek bir komut satırı,

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

"Myheap.bin" çıktısı insan tarafından okunamıyor (çoğumuz için) ve bunu analiz etmek için bir araca ihtiyacınız olacak. Benim tercihim MAT. http://www.eclipse.org/mat/


3
Benim linux Ctrl-C keser (sonlandırır), ben Ctrl- \
nafg

Düşünün bu "Windows üzerinde bir iplik dökümü CTRL + BREAK almak" ve üzerindeki genel etkisi. Aslında üreticinin mühendislik kararına bağlıdır. FE, Lenova, IIRC, cntrl + fn + p'dir.
ChiefTwoPencils

30

Linux işleminde .hprof dosyası oluşturmanın en iyi yolunun jmap komutu olduğunu düşünüyorum. Örneğin:jmap -dump:format=b,file=filename.hprof {PID}


19

Bahsedilen jconsole / visualvm kullanmaya ek olarak jstack -l <vm-id>, başka bir komut satırı penceresinde kullanabilir ve bu çıktıyı yakalayabilirsiniz.

<vm-id>, görev yöneticisi (pencereler ve unix'teki işlem kimliği) veya kullanılarak bulunabilir jps.

Hem jstackve jpsvardır Güneş JDK sürüm 6 ve üzeri sayılabilir.


Bu araçlar Java 1.6'da desteklenmez. Java 1.6 sadece jconsole sahiptir.
Vanchinathan Chandrasekaran

7
JDK ve JRE'yi karıştırıyor olabilirsiniz, JDK'dan açıkça bahsetmiştim. Araçlar için belgelere bakın: download.oracle.com/javase/6/docs/technotes/tools/share/… ve download.oracle.com/javase/6/docs/technotes/tools/share/…
ankon

17

JDK (jvisualvm.exe) ile dağıtılan Java VisualVM'yi öneririm. Dinamik olarak bağlanabilir ve iş parçacıklarına ve yığınlara erişebilir. Bazı problemler için çok değerli buldum.


2
Çoğu zaman, ekli bir ek yüke sahip olduğu ve iplik dökümü genellikle üretim makinelerinden alındığı için mümkün değildir.
Hammad Dar

asıl soru 'çalışmayan' bir süreçle ilgilidir. Muhtemelen jvisualvm bağlanamıyor.
Jaberino

3
@Jaberino: Hayır, şu anda Windows'da çalışan ve konsolla ilişkili olmayan bir Java işlemi hakkında.
Lawrence Dol

En son java sürümlerinde Java VisualVM'in yerini JMC / JFR üstlendi . Ayrıca bkz. JVisualVM ve Java Mission Control arasındaki farklar nelerdir?
Vadzim

16

Server-jre 8 ve üstü içindeyseniz bunu kullanabilirsiniz:

jcmd PID GC.heap_dump /tmp/dump

1
Üretim sistemlerinin çoğunda jdk değil sadece jre var. Bu yardımcı olur.
Pragalathan M

15

Aşağıdaki seçeneklerden birini deneyin.

  1. 32 bit JVM için:

    jmap -dump:format=b,file=<heap_dump_filename> <pid>
  2. 64 bit JVM için (açıkça alıntı):

    jmap -J-d64 -dump:format=b,file=<heap_dump_filename> <pid>
  3. VM parametrelerinde G1GC algoritmalı 64 bit JVM için (G1GC algoritmasıyla yalnızca canlı nesneler yığını oluşturulur):

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

İlgili SE sorusu: jmap komutuyla Java yığın dökümü hatası: Erken EOF

jmapBu makaledeki çeşitli seçeneklere göz atın


13

Yetersiz bellekte yığın yığını istiyorsanız, Java'yı şu seçenekle başlatabilirsiniz: -XX:-HeapDumpOnOutOfMemoryError

cf JVM Seçenekleri başvuru sayfası


Teşekkürler Daniel. Windows dosyasında bu dosya nerede oluşturulur? Varsayılan bir yol var mı?
lav

1
@lava Yolu Oracle'ın VM Seçenekleri sayfasında açıklandığı gibi -XX: HeapDumpPath üzerinden ayarlayabilirsiniz .
kamczak

Muhteşem. Bellek sızıntısı gösterme umuduyla bir gecede bir test yapmak istedim ama mevcut olmadığımda OOM ve çökme endişesi vardı. Bu harika.
Fesleğen

7

Çalıştırabilir jconsole(Java 6'nın SDK'sına dahildir) ve ardından Java uygulamanıza bağlanabilirsiniz. Size çalışan her Thread ve yığın izini gösterecektir.


açık arayla en iyi cevap! Şimdiye kadar bunu bilmiyordum ve gerçekten pratik!
Xerus

7

kill -3 <pid>Cygwin'den gönderebilirsiniz . psWindows işlemlerini bulmak için Cygwin seçeneklerini kullanmanız ve ardından sinyali bu işleme göndermeniz yeterlidir.



3

JDK 1.6 veya üstünü kullanıyorsanız jmap, bir Java işleminin yığın Dökümü almak için komutu kullanabilirsiniz , koşul ProcessID olarak bilinmelidir.

Windows Machine kullanıyorsanız, PID almak için Görev Yöneticisi'ni kullanabilirsiniz. Linux makine için sizin gibi komut çeşitleri kullanabilir ps -A | grep javaveya netstat -tupln | grep javaveyatop | grep java uygulamanıza bağlı olarak kullanabilirsiniz.

Sonra jmap -dump:format=b,file=sample_heap_dump.hprof 12341234'ün PID olduğu gibi komutu kullanabilirsiniz .

Hprof dosyasını yorumlamak için mevcut araç çeşitleri vardır . Oracle'ın kullanımı kolay olan visualvm aracını önereceğim.


3

Herhangi bir nedenle konsolu / terminali kullanamıyorsanız (veya istemiyorsanız), alternatif bir çözüm var. Java uygulamasının sizin için iş parçacığı dökümünü yazdırmasını sağlayabilirsiniz. Yığın İzi'ni toplayan kod oldukça basittir ve bir düğmeye veya web arabirimine eklenebilir.

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

Bu yöntem şuna benzer bir dize döndürür:

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)

Akışları olan bir Java 8 sürümüyle ilgilenenler için kod daha da kompakttır:

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

Bu kodu aşağıdakilerle kolayca test edebilirsiniz:

System.out.print(getThreadDump());

3

Aşağıdaki komut dosyası, başka bir Windows Oturumuna bağlanmak için PsExec'i kullanır, böylece Uzak Masaüstü Hizmeti üzerinden bağlandığında bile çalışır.

Ben iş parçacıkları, yığın, sistem özellikleri ve JVM argümanları döker Java 8 ( PsExecve kullanarak jcmd) adlı küçük bir toplu komut dosyası yazdı 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'yi başlatan kullanıcının aynı Windows oturumunda çalıştırılmalıdır, bu nedenle Uzak Masaüstü üzerinden bağlanırsanız bir komut istemi başlatmanız Session 0ve oradan çalıştırmanız gerekebilir . Örneğin

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

Bu View the message, etkileşimli oturumda sizden (alttaki görev çubuğu simgesini tıklatın) jvmdump.batkomut dosyasını çalıştırabileceğiniz diğer oturumda yeni konsola götürür .


2

Java uygulaması süreç kimliği nasıl alınır?

Java uygulamalarının işlem kimliğini almak için 'jcmd' komutunu yürütün.

Konu dökümü nasıl alınır?

jcmd PID Thread.print> thread.dump

Referans bağlantısı

İş parçacığı dökümünü almak için jstack bile kullanabilirsiniz (jstack PID> thread.dump). Referans bağlantısı

Yığın dökümü nasıl alınır?

Yığın dökümü almak için jmap aracını kullanın. jmap -F -dump: canlı, biçim = b, dosya = heap.bin PID

PID, uygulamanın işlem kimliğini ifade eder. Referans bağlantısı


1

Belki jcmd ?

Jcmd yardımcı programı, JVM'ye tanılama komut istekleri göndermek için kullanılır; burada bu istekler, Java Uçuş Kayıtlarını kontrol etmek, JVM ve Java Uygulamalarını gidermek ve teşhis etmek için yararlıdır.

Jcmd aracı, Oracle'ın Java 7 ile tanıtıldı ve özellikle JVM uygulamalarıyla ilgili sorunları Java işlemlerinin kimliklerini (benzer bir şekilde jps'e) tanımlamak, yığın yığınlarını (jmap gibi) almak, iplik yığınlarını (jstack'a benzer) tanımlamak için kullanarak sorun gidermede yararlıdır. ), sistem özellikleri ve komut satırı bayrakları (benzer - jinfo) gibi sanal makine özelliklerini görüntüleme ve çöp toplama istatistiklerini (benzer - jstat) edinme. Jcmd aracı "JVM uygulamanızla ilgili sorunları araştırmak ve çözmek için bir İsviçre çakısı" ve "gizli mücevher" olarak adlandırılmıştır.

Aşağıdakileri çağırırken kullanmanız gereken işlem şöyledir jcmd:

  1. Adresine git jcmd <pid> GC.heap_dump <file-path>
  2. Hangi
  3. pid: yığın dökümü yakalanacak bir Java Process Id'dir.
  4. dosya yolu: yığın dökümünün yazdırıldığı bir dosya yoludur.

Java yığın dökümü alma hakkında daha fazla bilgi için göz atın .


0

Visualvm takibi:

Doğru JVM bağımsız değişkenleriyle (ve uzaktaki kutuda) başlatmadığınız için jvisualvm'den çalışan JVM'nize "bağlanamazsanız", jstatd , ardından doğrudan bağlantınız olduğunu varsayarak, visualvm'de "uzak ana bilgisayar" olarak, ana bilgisayar adını çift tıklayın ve bu kutudaki diğer tüm JVM'ler visualvm'de sihirli bir şekilde görünecektir.

Bu kutudaki bağlantı noktalarına "doğrudan bağlantınız" yoksa, bunu bir proxy üzerinden de yapabilirsiniz .

İstediğiniz işlemi gördüğünüzde, jvisualvm'de detaylandırın ve monitör sekmesini kullanın -> "heapdump" düğmesini kullanın.


0

Aşağıdaki java kodu PID sağlayarak bir Java Süreci Yığın Dökümü almak için kullanılır. Program yığın yığını dökümü için Uzak JMX bağlantısı kullanır. Bazıları için yararlı olabilir.

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'ta bir alt java işleminden iplik dökümü / yığın dökümü almak için, ilk adım olarak alt işlem kimliğini tanımlamanız gerekir.

Jps komutunu vererek, Windows makinenizde çalışan tüm java işlemi kimliklerini elde edebilirsiniz. Bu listeden alt işlem kimliği seçmeniz gerekir. Alt işlem kimliğine sahip olduğunuzda, iplik dökümü ve yığın dökümlerini yakalamak için çeşitli seçenekler vardır.

Konu Dökümlerini Yakalama:

İplik dökümlerini yakalamak için 8 seçenek vardır:

  1. jstack
  2. -3 öldür
  3. jvisualVM
  4. JMC
  5. Windows (Ctrl + Break)
  6. ThreadMXBean
  7. APM Araçları
  8. Jcmd

Her seçenekle ilgili ayrıntılar bu makalede bulunabilir . İplik dökümlerini yakaladıktan sonra fastThread , Samuraito iplik dökümlerini analiz edebilirsiniz.

Öbek Dökümü Yakalama:

Yığın dökümlerini yakalamak için 7 seçenek vardır:

  1. JMAP

  2. XX: + HeapDumpOnOutOfMemoryError

  3. Jcmd

  4. JVisualVM

  5. JMX

  6. Programlı Yaklaşım

  7. Yönetim konsolları

Her seçenekle ilgili ayrıntılar bu makalede bulunabilir . Yığın dökümünü yakaladıktan sonra , yakalanan yığın dökümlerini analiz etmek için Eclipse Bellek Analizi aracı , HeapHero gibi araçları kullanabilirsiniz .


-1

Oracle JDK'da jmap (Java Home bin klasöründe bulunur) adlı bir komutumuz var. komutun kullanımı aşağıdaki gibi gelir

jmap (seçenek) (pid)

Örnek: jmap -dump: canlı, biçim = b, dosya = heap.bin (pid)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.