ããã¯ããªã«ãããããŠæžãããã®ïŒ
ã³ã³ããç°å¢ãªã©ã§Javaã¢ããªã±ãŒã·ã§ã³ãå®è¡ããŠããæã§ãã€JDKãã€ã³ã¹ããŒã«ããŠããªãå Žåãjcmdçã®JDKä»å±ããŒã«ããªããŠ
å°ãå Žåãªã©ããããšæããŸãã
ããããæã«ã¯jattachãšããããŒã«ã䜿ããšäŸ¿å©ãããªã®ã§è©ŠããŠã¿ãŸããã
jattach
jattachã®GitHubãªããžããªãŒã¯ãã¡ãã
GitHub - jattach/jattach: JVM Dynamic Attach utility
jattachã¯åçã¢ã¿ããã¡ã«ããºã ã䜿çšããŠJVMããã»ã¹ã«ã³ãã³ããéä¿¡ãããŠãŒãã£ãªãã£ããšãããŠããŸãã
The utility to send commands to a JVM process via Dynamic Attach mechanism.
jmapãjstackãjcmdãjjinfoã䜿ããã·ã³ã°ã«ãã€ããªãªããã°ã©ã ãšãããŠããŠãJDKã¯å¿ èŠãªãJREã®ã¿ã§åäœããŸãã
All-in-one jmap + jstack + jcmd + jinfo functionality in a single tiny program.
No installed JDK required, works with just JRE. Supports Linux containers.
Attach APIã®è»œéãªãã€ãã£ãããŒãžã§ã³ã ãšãããŠããŸãïŒAttach APIã䜿ã£ãŠããããã§ã¯ãããŸããïŒã
çŸåšã®ããŒãžã§ã³ã¯2.2ã§ããµããŒãããŠããã³ãã³ãã¯ä»¥äžãšãªã£ãŠããŸãã
- load : load agent library
- properties : print system properties
- agentProperties : print agent properties
- datadump : show heap and thread summary
- threaddump : dump all stack traces (like jstack)
- dumpheap : dump heap (like jmap)
- inspectheap : heap histogram (like jmap -histo)
- setflag : modify manageable VM flag
- printflag : print VM flag
- jcmd : execute jcmd command
ããã§MercurialãªããžããªãŒãžã®ãªã³ã¯ãåºå
žçã«è²ŒãããŠããã®ã§ããããã§ã«ãªããªã£ãŠããã®ã§ä»£ããã«GitHubãªããžããªãŒãžã®
ãªã³ã¯ãèŒããŠãããŸãã
Mercurialã®æã®ãªããžã§ã³ãè¡çªå·ãšã¯å®å šã«äžèŽããŠã¯ããŸããããå 容çã«ããã§ãããâŠã
ããŠã³ããŒãã§ãããã€ããªãŒãèŠããšãLinuxãmacOSãWindowsã®ãããã§ã䜿ãããã§ãã
Release Concatenate jcmd arguments · jattach/jattach · GitHub
䜿ãæ¹ãšããŠã¯
$ jattach [pid] [command]
ãšãã圢åŒã«ãªããŸãã
ããã§ã¯è©ŠããŠã¿ãŸãããã
åèïŒ
JRE しか入ってない Pod で Java の heap dump を取りたい / Get heap dump on JRE container - Speaker Deck
ç°å¢
ä»åã®ç°å¢ã¯ãã¡ãã
$ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.4 LTS Release: 22.04 Codename: jammy $ uname -srvmpio Linux 5.15.0-94-generic #104-Ubuntu SMP Tue Jan 9 15:25:40 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
Ubuntu Linux 22.04 LTSã§ãã
ãé¡
ç°¡åãªJavaããã°ã©ã ãæžããJREã®ã¿ãã€ã³ã¹ããŒã«ããè€æ°ã®JavaããŒãžã§ã³ïŒ8ã21ãŸã§ã®LTSïŒã®çµã¿åããã§jattachã
åäœãããèŠãŠãããããšæããŸãã
ãé¡ã¯ä»¥äžã®ããã°ã©ã ã«ããŸãã
Server.java
import java.io.IOException; import java.io.OutputStream; import java.net.InetSocketAddress; import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; import java.util.concurrent.Executors; import com.sun.net.httpserver.HttpServer; public class Server { public static void main(String... args) throws IOException { int port = Integer.parseInt(System.getProperty("server.port", "8000")); HttpServer server = HttpServer.create(new InetSocketAddress(port), 0); server.createContext("/", exchange -> { String message = "Hello World"; byte[] bytes = message.getBytes(StandardCharsets.UTF_8); exchange.sendResponseHeaders(200, bytes.length); try (OutputStream os = exchange.getResponseBody()) { os.write(bytes); } }); server.setExecutor(Executors.newCachedThreadPool()); server.start(); System.out.printf("[%s] start lightweight http server.%n", LocalDateTime.now()); } }
JDKã«ä»å±ããŠããHTTPãµãŒããŒã䜿ã£ãããã°ã©ã ã§ããå°ããããšãããã§ãããã·ã¹ãã ããããã£ã䜿ãããã«ããŠããŸãã
ãã¡ãã¯å
ã«ã³ã³ãã€ã«ããŠããå¿
èŠãããã®ã§ãå¥ã«JDKãã€ã³ã¹ããŒã«ããç°å¢ã§äœæããŠä»åã®äžéããŒãžã§ã³ã§ãã
Java 8åãã«ã³ã³ãã€ã«ããŸãã
$ javac --release 8 Server.java
äœæã¯Java 21ã§è¡ã£ãŠããŸãã
$ java --version openjdk 21.0.1 2023-10-17 OpenJDK Runtime Environment (build 21.0.1+12-Ubuntu-222.04) OpenJDK 64-Bit Server VM (build 21.0.1+12-Ubuntu-222.04, mixed mode, sharing)
ãã®Javaã䜿ãã®ã¯ãããŸã§ã§ãã
JREã®ã¿ã®Javaãã€ã³ã¹ããŒã«ãã
ãŸãã¯JREã®ã¿ã®Javaãã€ã³ã¹ããŒã«ããŸãã
$ sudo apt install openjdk-8-jre-headless openjdk-11-jre-headless openjdk-17-jre-headless openjdk-21-jre-headless
ã¡ãªã¿ã«ãJDKãã€ã³ã¹ããŒã«ããå Žåã¯openjdk-21-jdk-headless
ãopenjdk-21-jdk-headless
ãšãã£ãæãã§ãã
ã€ã³ã¹ããŒã«ãããããŒãžã§ã³ã
$ /usr/lib/jvm/java-8-openjdk-amd64/bin/java -version openjdk version "1.8.0_392" OpenJDK Runtime Environment (build 1.8.0_392-8u392-ga-1~22.04-b08) OpenJDK 64-Bit Server VM (build 25.392-b08, mixed mode) $ /usr/lib/jvm/java-11-openjdk-amd64/bin/java --version openjdk 11.0.21 2023-10-17 OpenJDK Runtime Environment (build 11.0.21+9-post-Ubuntu-0ubuntu122.04) OpenJDK 64-Bit Server VM (build 11.0.21+9-post-Ubuntu-0ubuntu122.04, mixed mode, sharing) $ /usr/lib/jvm/java-17-openjdk-amd64/bin/java --version openjdk 17.0.9 2023-10-17 OpenJDK Runtime Environment (build 17.0.9+9-Ubuntu-122.04) OpenJDK 64-Bit Server VM (build 17.0.9+9-Ubuntu-122.04, mixed mode, sharing) $ /usr/lib/jvm/java-21-openjdk-amd64/bin/java --version openjdk 21.0.1 2023-10-17 OpenJDK Runtime Environment (build 21.0.1+12-Ubuntu-222.04) OpenJDK 64-Bit Server VM (build 21.0.1+12-Ubuntu-222.04, mixed mode, sharing)
JREã®ã¿ãªã®ã§ãjcmdçã¯å ¥ã£ãŠããŸããã
$ /usr/lib/jvm/java-21-openjdk-amd64/bin/javac -bash: /usr/lib/jvm/java-21-openjdk-amd64/bin/javac: ãã®ãããªãã¡ã€ã«ããã£ã¬ã¯ããªã¯ãããŸãã $ /usr/lib/jvm/java-21-openjdk-amd64/bin/jcmd -bash: /usr/lib/jvm/java-21-openjdk-amd64/bin/jcmd: ãã®ãããªãã¡ã€ã«ããã£ã¬ã¯ããªã¯ãããŸãã
å ã»ã©äœæããããã°ã©ã ãåããŒãžã§ã³ã§åäœããããšã確èªããŠãããŸãã
## Java 8 $ /usr/lib/jvm/java-8-openjdk-amd64/bin/java -Dserver.port=8080 Server [2024-02-18T15:26:46.535] start lightweight http server. $ curl localhost:8080 Hello World ## Java 11 $ /usr/lib/jvm/java-11-openjdk-amd64/bin/java -Dserver.port=8080 Server [2024-02-18T15:27:56.106774] start lightweight http server. $ curl localhost:8080 Hello World ## Java 17 $ /usr/lib/jvm/java-17-openjdk-amd64/bin/java -Dserver.port=8080 Server [2024-02-18T15:28:22.205653282] start lightweight http server. $ curl localhost:8080 Hello World ## Java 21 $ /usr/lib/jvm/java-21-openjdk-amd64/bin/java -Dserver.port=8080 Server [2024-02-18T15:28:43.328222880] start lightweight http server. $ curl localhost:8080 Hello World
ããã§æºåã¯ã§ããŸããã
jattachãã€ã³ã¹ããŒã«ãã
jattachãã€ã³ã¹ããŒã«ããŸãããã Ubuntu Linuxã®å Žåã¯aptã§ã€ã³ã¹ããŒã«ããããšãã§ããã®ã§ãã
$ sudo apt install jattach
GitHubã®ReleasesããååŸããããšãå€ãããªæ°ãããã®ã§ããã¡ãã«ããŠãããŸãã
apt show
ã§èŠããšãããªæãã«ãªã£ãŠããŸããããŒãžã§ã³ã¯ææ°çã§ã¯ãªãã§ããã
$ apt show jattach Package: jattach Version: 2.0-1 Priority: optional Section: universe/java Origin: Ubuntu Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com> Original-Maintainer: Sven Hoexter <hoexter@debian.org> Bugs: https://bugs.launchpad.net/ubuntu/+filebug Installed-Size: 47.1 kB Depends: libc6 (>= 2.34) Homepage: https://github.com/apangin/jattach Download-Size: 12.4 kB APT-Sources: https://mirrors.edge.kernel.org/ubuntu jammy/universe amd64 Packages Description: JVM Dynamic Attach utility all in one jmap jstack jcmd jinfo jattach is a utility implementing commands for the JVM Dynamic Attach mechanism. Instead of installing a complete JDK you can use this small utility to query information from your running JVM.
ã§ã¯ãReleasesããããŠã³ããŒãããŠå±éã
$ curl -LO https://github.com/jattach/jattach/releases/download/v2.2/jattach-linux-x64.tgz $ tar xf jattach-linux-x64.tgz
jattach
ãšããã·ã³ã°ã«ãã€ããªã®ãã¡ã€ã«ãçŸããŸãã
åŒæ°ãªãã§å®è¡ãããšãããŒãžã§ã³ãšãã«ãã衚瀺ãããŸãã
$ ./jattach jattach 2.2 built on Jan 10 2024 Usage: jattach <pid> <cmd> [args ...] Commands: load threaddump dumpheap setflag properties jcmd inspectheap datadump printflag agentProperties
ãšãããããJava 21ãã¿ãŒã²ããã«ããŠè©ŠããŠã¿ãŸãããã
$ /usr/lib/jvm/java-21-openjdk-amd64/bin/java -Xmx512M -Dtarget.port=8080 Server [2024-02-18T15:41:31.273379805] start lightweight http server.
ãŸãã¯pidãååŸãããšããããã§ãããããèªäœãjattachã®jcmdã«é Œãããšã¯ã§ããŸãããå ã«pidãæå®ããå¿ èŠãããããã§ããã
$ ./jattach jcmd jattach 2.2 built on Jan 10 2024 Usage: jattach <pid> <cmd> [args ...] Commands: load threaddump dumpheap setflag properties jcmd inspectheap datadump printflag agentProperties $ ./jattach jcmd -l jcmd is not a valid process ID
䜿ããã³ãã³ãã¯ä»¥äžãšããããšã§ããã
- load : load agent library
- properties : print system properties
- agentProperties : print agent properties
- datadump : show heap and thread summary
- threaddump : dump all stack traces (like jstack)
- dumpheap : dump heap (like jmap)
- inspectheap : heap histogram (like jmap -histo)
- setflag : modify manageable VM flag
- printflag : print VM flag
- jcmd : execute jcmd command
ãã«ãã§è¡šç€ºãããŠããã³ãã³ããšèŠæ¯ã¹ããšãjcmdã¯äœ¿ããŸããjmapãjstackãjinfoã¯äŒŒã圢æ ã§äœ¿ãããšããããšã«æ°ã¥ããŸãã
å®éãããšãã°jstackãæå®ããŠã䜿ããŸããã
$ ./jattach 3745 jstack Connected to remote JVM JVM response code = -1 Operation jstack not recognized!
ãªã®ã§ãjmapãjstackãjinfoã䜿ãããå Žåã¯jcmdã§ä»£æ¿ããããã«ãã«åŸã£ãŠå¥ã®ã³ãã³ãã䜿ãããšã«ãªããŸãã
ããã€ãè©ŠããŠã¿ãŸããããjattach [pid] properties
ã§ã·ã¹ãã ããããã£ã®è¡šç€ºã
$ ./jattach 3745 properties Connected to remote JVM JVM response code = 0 #Sun Feb 18 15:47:26 JST 2024 file.encoding=UTF-8 file.separator=/ java.class.path=. java.class.version=65.0 java.home=/usr/lib/jvm/java-21-openjdk-amd64 java.io.tmpdir=/tmp java.library.path=/usr/java/packages/lib\:/usr/lib/x86_64-linux-gnu/jni\:/lib/x86_64-linux-gnu\:/usr/lib/x86_64-linux-gnu\:/usr/lib/jni\:/lib\:/usr/lib java.runtime.name=OpenJDK Runtime Environment java.runtime.version=21.0.1+12-Ubuntu-222.04 java.specification.name=Java Platform API Specification java.specification.vendor=Oracle Corporation java.specification.version=21 java.vendor=Private Build java.vendor.url=Unknown java.vendor.url.bug=Unknown java.version=21.0.1 java.version.date=2023-10-17 java.vm.compressedOopsMode=32-bit java.vm.info=mixed mode, sharing java.vm.name=OpenJDK 64-Bit Server VM java.vm.specification.name=Java Virtual Machine Specification java.vm.specification.vendor=Oracle Corporation java.vm.specification.version=21 java.vm.vendor=Private Build java.vm.version=21.0.1+12-Ubuntu-222.04 jdk.debug=release line.separator=\n native.encoding=UTF-8 os.arch=amd64 os.name=Linux os.version=5.15.0-94-generic path.separator=\: stderr.encoding=UTF-8 stdout.encoding=UTF-8 sun.arch.data.model=64 sun.boot.library.path=/usr/lib/jvm/java-21-openjdk-amd64/lib sun.cpu.endian=little sun.io.unicode.encoding=UnicodeLittle sun.java.command=Server sun.java.launcher=SUN_STANDARD sun.jnu.encoding=UTF-8 sun.management.compiler=HotSpot 64-Bit Tiered Compilers target.port=8080 ãçç¥ã user.timezone=Asia/Tokyo
ããã¯jattachåºæã®éšåã§ãã
Connected to remote JVM JVM response code = 0
jattach [pid] agentProperties
ã
$ ./jattach 3745 agentProperties Connected to remote JVM JVM response code = 0 #Sun Feb 18 15:53:30 JST 2024 sun.java.command=Server sun.jvm.args=-Xmx512M -Dtarget.port\=8080 sun.jvm.flags=
jattach [pid] threaddump
ã§ã¹ã¬ãããã³ãã
$ ./jattach 3745 threaddump Connected to remote JVM JVM response code = 0 2024-02-18 15:50:41 Full thread dump OpenJDK 64-Bit Server VM (21.0.1+12-Ubuntu-222.04 mixed mode, sharing): Threads class SMR info: _java_thread_list=0x00007fe7a40024f0, length=13, elements={ 0x00007fe8340ae000, 0x00007fe8340af680, 0x00007fe8340b1110, 0x00007fe8340b2750, 0x00007fe8340b3cf0, 0x00007fe8340b5830, 0x00007fe8340b6ef0, 0x00007fe8340c5100, 0x00007fe8340c8a50, 0x00007fe8340fa8f0, 0x00007fe83410aa70, 0x00007fe8340162d0, 0x00007fe7a4000fe0 } "Reference Handler" #9 [3754] daemon prio=10 os_prio=0 cpu=0.49ms elapsed=549.96s tid=0x00007fe8340ae000 nid=3754 waiting on condition [0x00007fe80db0e000] java.lang.Thread.State: RUNNABLE at java.lang.ref.Reference.waitForReferencePendingList(java.base@21.0.1/Native Method) at java.lang.ref.Reference.processPendingReferences(java.base@21.0.1/Reference.java:246) at java.lang.ref.Reference$ReferenceHandler.run(java.base@21.0.1/Reference.java:208) "Finalizer" #10 [3755] daemon prio=8 os_prio=0 cpu=0.32ms elapsed=549.96s tid=0x00007fe8340af680 nid=3755 in Object.wait() [0x00007fe80da0e000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait0(java.base@21.0.1/Native Method) - waiting on <0x00000000e1f01670> (a java.lang.ref.NativeReferenceQueue$Lock) at java.lang.Object.wait(java.base@21.0.1/Object.java:366) at java.lang.Object.wait(java.base@21.0.1/Object.java:339) at java.lang.ref.NativeReferenceQueue.await(java.base@21.0.1/NativeReferenceQueue.java:48) at java.lang.ref.ReferenceQueue.remove0(java.base@21.0.1/ReferenceQueue.java:158) at java.lang.ref.NativeReferenceQueue.remove(java.base@21.0.1/NativeReferenceQueue.java:89) - locked <0x00000000e1f01670> (a java.lang.ref.NativeReferenceQueue$Lock) at java.lang.ref.Finalizer$FinalizerThread.run(java.base@21.0.1/Finalizer.java:173) "Signal Dispatcher" #11 [3756] daemon prio=9 os_prio=0 cpu=0.70ms elapsed=549.96s tid=0x00007fe8340b1110 nid=3756 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Service Thread" #12 [3757] daemon prio=9 os_prio=0 cpu=0.18ms elapsed=549.96s tid=0x00007fe8340b2750 nid=3757 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Monitor Deflation Thread" #13 [3758] daemon prio=9 os_prio=0 cpu=161.02ms elapsed=549.96s tid=0x00007fe8340b3cf0 nid=3758 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "C2 CompilerThread0" #14 [3759] daemon prio=9 os_prio=0 cpu=81.61ms elapsed=549.96s tid=0x00007fe8340b5830 nid=3759 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE No compile task "C1 CompilerThread0" #15 [3760] daemon prio=9 os_prio=0 cpu=126.57ms elapsed=549.96s tid=0x00007fe8340b6ef0 nid=3760 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE No compile task "Notification Thread" #16 [3761] daemon prio=9 os_prio=0 cpu=0.21ms elapsed=549.95s tid=0x00007fe8340c5100 nid=3761 runnable [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Common-Cleaner" #17 [3762] daemon prio=8 os_prio=0 cpu=2.68ms elapsed=549.94s tid=0x00007fe8340c8a50 nid=3762 waiting on condition [0x00007fe80d30e000] java.lang.Thread.State: TIMED_WAITING (parking) at jdk.internal.misc.Unsafe.park(java.base@21.0.1/Native Method) - parking to wait for <0x00000000e1f10390> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.parkNanos(java.base@21.0.1/LockSupport.java:269) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(java.base@21.0.1/AbstractQueuedSynchronizer.java:1847) at java.lang.ref.ReferenceQueue.await(java.base@21.0.1/ReferenceQueue.java:71) at java.lang.ref.ReferenceQueue.remove0(java.base@21.0.1/ReferenceQueue.java:143) at java.lang.ref.ReferenceQueue.remove(java.base@21.0.1/ReferenceQueue.java:218) at jdk.internal.ref.CleanerImpl.run(java.base@21.0.1/CleanerImpl.java:140) at java.lang.Thread.runWith(java.base@21.0.1/Thread.java:1596) at java.lang.Thread.run(java.base@21.0.1/Thread.java:1583) at jdk.internal.misc.InnocuousThread.run(java.base@21.0.1/InnocuousThread.java:186) "idle-timeout-task" #18 [3763] daemon prio=5 os_prio=0 cpu=9.68ms elapsed=549.87s tid=0x00007fe8340fa8f0 nid=3763 in Object.wait() [0x00007fe80d20e000] java.lang.Thread.State: TIMED_WAITING (on object monitor) at java.lang.Object.wait0(java.base@21.0.1/Native Method) - waiting on <0x00000000e1fa5fa0> (a java.util.TaskQueue) at java.lang.Object.wait(java.base@21.0.1/Object.java:366) at java.util.TimerThread.mainLoop(java.base@21.0.1/Timer.java:563) - locked <0x00000000e1fa5fa0> (a java.util.TaskQueue) at java.util.TimerThread.run(java.base@21.0.1/Timer.java:516) "HTTP-Dispatcher" #19 [3764] prio=5 os_prio=0 cpu=89.43ms elapsed=549.84s tid=0x00007fe83410aa70 nid=3764 runnable [0x00007fe80d10e000] java.lang.Thread.State: RUNNABLE at sun.nio.ch.EPoll.wait(java.base@21.0.1/Native Method) at sun.nio.ch.EPollSelectorImpl.doSelect(java.base@21.0.1/EPollSelectorImpl.java:121) at sun.nio.ch.SelectorImpl.lockAndDoSelect(java.base@21.0.1/SelectorImpl.java:130) - locked <0x00000000e1fa3308> (a sun.nio.ch.Util$2) - locked <0x00000000e1fa2f80> (a sun.nio.ch.EPollSelectorImpl) at sun.nio.ch.SelectorImpl.select(java.base@21.0.1/SelectorImpl.java:142) at sun.net.httpserver.ServerImpl$Dispatcher.run(jdk.httpserver@21.0.1/ServerImpl.java:474) at java.lang.Thread.runWith(java.base@21.0.1/Thread.java:1596) at java.lang.Thread.run(java.base@21.0.1/Thread.java:1583) "DestroyJavaVM" #20 [3746] prio=5 os_prio=0 cpu=172.46ms elapsed=549.80s tid=0x00007fe8340162d0 nid=3746 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "Attach Listener" #21 [3775] daemon prio=9 os_prio=0 cpu=39.40ms elapsed=260.89s tid=0x00007fe7a4000fe0 nid=3775 waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "VM Thread" os_prio=0 cpu=43.51ms elapsed=549.97s tid=0x00007fe8340a0e10 nid=3753 runnable "GC Thread#0" os_prio=0 cpu=0.34ms elapsed=550.01s tid=0x00007fe834042490 nid=3747 runnable "G1 Main Marker" os_prio=0 cpu=0.30ms elapsed=550.01s tid=0x00007fe834047a50 nid=3748 runnable "G1 Conc#0" os_prio=0 cpu=0.19ms elapsed=550.01s tid=0x00007fe8340489f0 nid=3749 runnable "G1 Refine#0" os_prio=0 cpu=0.24ms elapsed=550.01s tid=0x00007fe83406ccc0 nid=3750 runnable "G1 Service" os_prio=0 cpu=42.37ms elapsed=550.01s tid=0x00007fe83406dc70 nid=3751 runnable "VM Periodic Task Thread" os_prio=0 cpu=865.36ms elapsed=549.98s tid=0x00007fe834086b50 nid=3752 waiting on condition JNI global refs: 12, weak refs: 0
pidã®äœçœ®ã¯å€ãããŸãããjattach [pid] jcmd Thread.print
ã§ãOKã§ãã
$ ./jattach 3745 jcmd Thread.print Connected to remote JVM JVM response code = 0 2024-02-18 15:51:35 Full thread dump OpenJDK 64-Bit Server VM (21.0.1+12-Ubuntu-222.04 mixed mode, sharing): Threads class SMR info: _java_thread_list=0x00007fe7a40024f0, length=13, elements={ 0x00007fe8340ae000, 0x00007fe8340af680, 0x00007fe8340b1110, 0x00007fe8340b2750, 0x00007fe8340b3cf0, 0x00007fe8340b5830, 0x00007fe8340b6ef0, 0x00007fe8340c5100, 0x00007fe8340c8a50, 0x00007fe8340fa8f0, 0x00007fe83410aa70, 0x00007fe8340162d0, 0x00007fe7a4000fe0 } "Reference Handler" #9 [3754] daemon prio=10 os_prio=0 cpu=0.49ms elapsed=604.39s tid=0x00007fe8340ae000 nid=3754 waiting on condition [0x00007fe80db0e000] java.lang.Thread.State: RUNNABLE at java.lang.ref.Reference.waitForReferencePendingList(java.base@21.0.1/Native Method) at java.lang.ref.Reference.processPendingReferences(java.base@21.0.1/Reference.java:246) at java.lang.ref.Reference$ReferenceHandler.run(java.base@21.0.1/Reference.java:208) ãçç¥ã JNI global refs: 12, weak refs: 0
jcmdã®Thread.dump_to_file
ã¯äœ¿ãããã§ããããïŒ
$ ./jattach 3745 jcmd Thread.dump_to_file -format=json thread_dump.json Connected to remote JVM JVM response code = 0 Created $HOME/thread_dump.json
䜿ããŸããâŠã
$ head -n 10 thread_dump.json { "threadDump": { "processId": "3745", "time": "2024-02-18T06:55:01.331346937Z", "runtimeVersion": "21.0.1+12-Ubuntu-222.04", "threadContainers": [ { "container": "<root>", "parent": null, "owner": null,
ä»ã®ããŒãžã§ã³ã®JREã«åãã³ãã³ãã䜿ã£ãŠãåœç¶ã§ããåãä»ããŠããããŸããã
## 3805ã¯Java 17ã§åäœãããŠããããã°ã©ã ã®pid $ ./jattach 3805 jcmd Thread.dump_to_file -format=json thread_dump.json Connected to remote JVM JVM response code = -1 java.lang.IllegalArgumentException: Unknown diagnostic command
ãŸããéåžžã®jcmdã ãšpidã®ã¿æå®ããŠå®è¡ãããšäœ¿çšã§ããã³ãã³ãã衚瀺ãããŸããããã®jcmdã ãšãã®æ©èœã¯å 容ã§ãã
$ ./jattach 3840 jcmd Connected to remote JVM JVM response code = 0
ãããŸã§ã¯Java 21ã§ç¢ºèªããŠããŸããããããšã®ããŒãžã§ã³ããã£ãã確èªããŠãããŸãããã
## Java 8 $ /usr/lib/jvm/java-8-openjdk-amd64/bin/java -Xmx512M -Dtarget.port=8080 Server [2024-02-18T16:02:21.863] start lightweight http server. $ ./jattach 3866 properties | grep '^java.*version' java.vm.version=25.392-b08 java.runtime.version=1.8.0_392-8u392-ga-1~22.04-b08 java.class.version=52.0 java.specification.version=1.8 java.vm.specification.version=1.8 java.version=1.8.0_392 java.specification.maintenance.version=5 $ ./jattach 3866 threaddump | head Connected to remote JVM JVM response code = 0 2024-02-18 16:03:27 Full thread dump OpenJDK 64-Bit Server VM (25.392-b08 mixed mode): "Attach Listener" #12 daemon prio=9 os_prio=0 tid=0x00007f0e48001000 nid=0xf2b waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE "DestroyJavaVM" #11 prio=5 os_prio=0 tid=0x00007f0e7400a000 nid=0xf1b waiting on condition [0x0000000000000000] java.lang.Thread.State: RUNNABLE ## Java 11 $ /usr/lib/jvm/java-11-openjdk-amd64/bin/java -Xmx512M -Dtarget.port=8080 Server [2024-02-18T16:03:49.186818] start lightweight http server. $ ./jattach 3893 properties | grep '^java.*version' java.specification.version=11 java.vm.specification.version=11 java.version.date=2023-10-17 java.runtime.version=11.0.21+9-post-Ubuntu-0ubuntu122.04 java.version=11.0.21 java.vm.version=11.0.21+9-post-Ubuntu-0ubuntu122.04 java.specification.maintenance.version=2 java.class.version=55.0 $ ./jattach 3893 threaddump | head Connected to remote JVM JVM response code = 0 2024-02-18 16:04:07 Full thread dump OpenJDK 64-Bit Server VM (11.0.21+9-post-Ubuntu-0ubuntu122.04 mixed mode, sharing): Threads class SMR info: _java_thread_list=0x00007fab1c000c40, length=12, elements={ 0x00007fab60092000, 0x00007fab60094000, 0x00007fab60099800, 0x00007fab6009b800, 0x00007fab6009d800, 0x00007fab6009f800, 0x00007fab600a1800, 0x00007fab600d5000, 0x00007fab600fb000, 0x00007fab6016b800, 0x00007fab60015000, 0x00007fab1c001000 ## Java 17 $ /usr/lib/jvm/java-17-openjdk-amd64/bin/java -Xmx512M -Dtarget.port=8080 Server [2024-02-18T16:04:35.788345626] start lightweight http server. $ ./jattach 3920 properties | grep '^java.*version' java.specification.version=17 java.vm.specification.version=17 java.version.date=2023-10-17 java.runtime.version=17.0.9+9-Ubuntu-122.04 java.version=17.0.9 java.vm.version=17.0.9+9-Ubuntu-122.04 java.class.version=61.0 $ ./jattach 3920 threaddump | head Connected to remote JVM JVM response code = 0 2024-02-18 16:04:55 Full thread dump OpenJDK 64-Bit Server VM (17.0.9+9-Ubuntu-122.04 mixed mode, sharing): Threads class SMR info: _java_thread_list=0x00007f7a58001e40, length=14, elements={ 0x00007f7ae408fe30, 0x00007f7ae4091220, 0x00007f7ae40967c0, 0x00007f7ae4097b80, 0x00007f7ae4098fa0, 0x00007f7ae409a960, 0x00007f7ae409bea0, 0x00007f7ae409d320, 0x00007f7ae40aca40, 0x00007f7ae40b0080, 0x00007f7ae40d6a60, 0x00007f7ae40e3ed0,
ããããã§ããã
ã©ããªã£ãŠããã®ãïŒ
ãšããã§JREã®ã¿ã§å®è¡ã§ãããšããjattachã§ãããã©ãããä»çµã¿ã§å®çŸããŠããã®ã§ããããïŒ
ãœãŒã¹ã³ãŒããèŠããšãposixãšwindowsã«åãããŠããŸãã
https://github.com/jattach/jattach/tree/v2.2/src
posixã¯åŠçã®äž»äœã¯HotSpotãšOpenJ9ã«åãããŠããŸãã
https://github.com/jattach/jattach/blob/v2.2/src/posix/jattach_hotspot.c
https://github.com/jattach/jattach/blob/v2.2/src/posix/jattach_openj9.c
ä»åã¯HotSpotã®æ¹ãèŠãŠã¿ãŸãã
åŠçãèŠããšããœã±ããäœæ â ã³ãã³ãéä¿¡ â çµæã®åä¿¡ããšãã£ãæµãã®ããã§ãã
int jattach_hotspot(int pid, int nspid, int argc, char** argv, int print_output) { if (check_socket(nspid) != 0 && start_attach_mechanism(pid, nspid) != 0) { perror("Could not start attach mechanism"); return 1; } int fd = connect_socket(nspid); if (fd == -1) { perror("Could not connect to socket"); return 1; } if (print_output) { printf("Connected to remote JVM\n"); } if (write_command(fd, argc, argv) != 0) { perror("Error writing to socket"); close(fd); return 1; } int result = read_response(fd, argc, argv, print_output); close(fd); return result; }
https://github.com/jattach/jattach/blob/v2.2/src/posix/jattach_hotspot.c#L178-L204
ããã§ã®ãœã±ããã¯ãUnixãã¡ã€ã³ãœã±ããã®ããã§ãã
// Connect to UNIX domain socket created by JVM for Dynamic Attach static int connect_socket(int pid) { int fd = socket(PF_UNIX, SOCK_STREAM, 0); if (fd == -1) { return -1; } struct sockaddr_un addr; addr.sun_family = AF_UNIX; int bytes = snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/.java_pid%d", tmp_path, pid); if (bytes >= sizeof(addr.sun_path)) { addr.sun_path[sizeof(addr.sun_path) - 1] = 0; } if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { close(fd); return -1; } return fd; }
https://github.com/jattach/jattach/blob/v2.2/src/posix/jattach_hotspot.c#L83-L103
ãã®ãœã±ããã䜿ããã³ãã³ããéä¿¡ããŠ
// Send command with arguments to socket static int write_command(int fd, int argc, char** argv) { char buf[8192]; const char* const limit = buf + sizeof(buf); // jcmd has 2 arguments maximum; merge excessive arguments into one int cmd_args = argc >= 2 && strcmp(argv[0], "jcmd") == 0 ? 2 : argc >= 4 ? 4 : argc; // Protocol version char* p = stpncpy(buf, "1", sizeof(buf)) + 1; int i; for (i = 0; i < argc && p < limit; i++) { if (i >= cmd_args) p[-1] = ' '; p = stpncpy(p, argv[i], limit - p) + 1; } for (i = cmd_args; i < 4 && p < limit; i++) { *p++ = 0; } const char* q = p < limit ? p : limit; for (p = buf; p < q; ) { ssize_t bytes = write(fd, p, q - p); if (bytes <= 0) { return -1; } p += (size_t)bytes; } return 0; }
https://github.com/jattach/jattach/blob/v2.2/src/posix/jattach_hotspot.c#L105-L134
çµæãåä¿¡ããŸãã
// Mirror response from remote JVM to stdout static int read_response(int fd, int argc, char** argv, int print_output) { char buf[8192]; ssize_t bytes = read(fd, buf, sizeof(buf) - 1); if (bytes == 0) { fprintf(stderr, "Unexpected EOF reading response\n"); return 1; } else if (bytes < 0) { perror("Error reading response"); return 1; } // First line of response is the command result code buf[bytes] = 0; int result = atoi(buf); // Special treatment of 'load' command if (result == 0 && argc > 0 && strcmp(argv[0], "load") == 0) { size_t total = bytes; while (total < sizeof(buf) - 1 && (bytes = read(fd, buf + total, sizeof(buf) - 1 - total)) > 0) { total += (size_t)bytes; } bytes = total; // The second line is the result of 'load' command; since JDK 9 it starts from "return code: " buf[bytes] = 0; result = atoi(strncmp(buf + 2, "return code: ", 13) == 0 ? buf + 15 : buf + 2); } if (print_output) { // Mirror JVM response to stdout printf("JVM response code = "); do { fwrite(buf, 1, bytes, stdout); bytes = read(fd, buf, sizeof(buf)); } while (bytes > 0); printf("\n"); } return result; }
https://github.com/jattach/jattach/blob/v2.2/src/posix/jattach_hotspot.c#L136-L176
ã€ãŸããUnixãã¡ã€ã³ãœã±ããã䜿ã£ãRPCçãªåœ¢ã§å®çŸãããŠããŠãjattachã¯jcmdçã®ä»£ããã®æ©èœãå®è£
ããŠãããšããããã¯
JavaVMãžã®ã³ãã³ãéä¿¡ãæ©æž¡ããããããã«ãªã£ãŠããããšãããããŸãã
ãªã®ã§ã察象ã®Javaããã»ã¹ãåäœããŠããã°OKãjattachèªèº«ã¯Javaã«äŸåããã«åäœããããšããããšã«ãªã£ãŠããããã§ãã
ãããèŠããšãããšãã°jcmdã®Thread.dump_to_file
ãJava 21ã§ã®ã¿åäœããçç±ïŒãšãããJava 21ã§ã¡ãããšåããçç±ïŒã
ããããŸããã
ãããã«
JDKãªãã§jcmdçã®å皮蚺æããŒã«ãåãããjattachãè©ŠããŠã¿ãŸããã
å°å ¥ããã°ãã£ãããšäœ¿ãããŸãJavaã®ããŒãžã§ã³ã«ããã»ã©äŸåããŠããªããããªããšãããããŸããã䟿å©ã§ããã
ãããã°çšéçã«æŒãããŠãããšããã®ããªãšæããŸãã
å®çŸæ¹æ³ãèŠãŠãããããããæ¹ãããã®ããšåèã«ãªããŸããã