Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to run jcmd without the JDK?

Tags:

java

jmap

I'm trying to figure out how to drop jcmd.exe on a windows server installed at a client site so that we can troubleshoot heap and thread issues. Don't really want to install the full JDK since it complicates the environment.

jcmd.exe definitely wants some components from the JDK to run, but I'm unable to determine which ones. If I can get it down to a small set that we unzip into a folder, use it to capture data, and then destroy, that would be perfect.

Anybody know what JDK components jcmd needs to run?

like image 360
DaveyBob Avatar asked Oct 16 '25 19:10

DaveyBob


2 Answers

A quick examination of jcmd.exe reveals:

    ntdll.dll => /c/WINDOWS/SYSTEM32/ntdll.dll (0x7fff01820000)
    KERNEL32.DLL => /c/WINDOWS/system32/KERNEL32.DLL (0x7ffeff180000)
    KERNELBASE.dll => /c/WINDOWS/system32/KERNELBASE.dll (0x7ffefe810000)
    SYSFER.DLL => /c/WINDOWS/System32/SYSFER.DLL (0x54f10000)
    jli.dll => /c/apps/jdk1.8.0_121/bin/jli.dll (0x51ec0000)
    MSVCR100.dll => /c/apps/jdk1.8.0_121/bin/MSVCR100.dll (0x51c40000)
    ADVAPI32.dll => /c/WINDOWS/system32/ADVAPI32.dll (0x7ffefeeb0000)
    msvcrt.dll => /c/WINDOWS/system32/msvcrt.dll (0x7fff01720000)
    sechost.dll => /c/WINDOWS/system32/sechost.dll (0x7ffeff0c0000)
    RPCRT4.dll => /c/WINDOWS/system32/RPCRT4.dll (0x7ffefec20000)
    USER32.dll => /c/WINDOWS/system32/USER32.dll (0x7ffefef60000)
    COMCTL32.dll => /c/WINDOWS/WinSxS/amd64_microsoft.windows.common-controls_6595b64144ccf1df_6.0.10586.672_none_a2d6b3cea53ff843/COMCTL32.dll (0x7ffef8460000)
    GDI32.dll => /c/WINDOWS/system32/GDI32.dll (0x7ffeff230000)
    combase.dll => /c/WINDOWS/system32/combase.dll (0x7ffeff3c0000)
    bcryptPrimitives.dll => /c/WINDOWS/system32/bcryptPrimitives.dll (0x7ffefe540000)

It therefore appears that msvcr100.dll and jli.dll would be the only requisite components from the JDK. A super quick test seems to indicate that these three files will suffice, but I will admit my test situation may not have been perfect.

EDIT: Upon further examination, here is the minimum configuration I found that works. It may be possible to modify the directory structure somewhat and set things such as CLASSPATH, JAVA_HOME, and PATH. I did not explore all of the permutations.

.:
bin/  COPYRIGHT*  jre/  lib/  LICENSE*

./bin:
jcmd.exe*  jli.dll*  msvcr100.dll*

./jre:
bin/  COPYRIGHT*  lib/  LICENSE*

./jre/bin:
attach.dll*  java.dll*  jli.dll*  net.dll*  nio.dll*  server/  unpack.dll*  
verify.dll*  zip.dll*

./jre/bin/server:
classes.jsa*  jvm.dll*  Xusage.txt*

./jre/lib:
amd64/  rt.jar*

./jre/lib/amd64:
jvm.cfg*

./lib:
jvm.lib*  tools.jar*

I also left the COPYRIGHT and LICENSE files as I felt they were important.

Test:

bin\jcmd.exe 16696 Thread.print
16696:
2017-04-27 18:01:49
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.121-b13 mixed mode):

"Worker-32" #84 prio=5 os_prio=0 tid=0x000000001bcaf800 nid=0x416c in 
Object.wait() [0x00000000335ef000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    at org.eclipse.core.internal.jobs.WorkerPool.sleep(WorkerPool.java:188)
    - locked <0x00000000c21120a8> (a org.eclipse.core.internal.jobs.WorkerPool)
    at org.eclipse.core.internal.jobs.WorkerPool.startJob(WorkerPool.java:220)
    at org.eclipse.core.internal.jobs.Worker.run(Worker.java:52)

"Worker-31" #83 prio=5 os_prio=0 tid=0x000000001bcb7800 nid=0x315c in 
Object.wait() [0x00000000312ef000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    at org.eclipse.core.internal.jobs.WorkerPool.sleep(WorkerPool.java:188)
    - locked <0x00000000c21120a8> (a org.eclipse.core.internal.jobs.WorkerPool)
    at org.eclipse.core.internal.jobs.WorkerPool.startJob(WorkerPool.java:220)
    at org.eclipse.core.internal.jobs.Worker.run(Worker.java:52)

<snip>...


F:\tmp\t1>bin\jcmd 16696 VM.flags
16696:
-XX:CICompilerCount=4 -XX:InitialHeapSize=268435456 
-XX:MaxHeapSize=1073741824 -XX:MaxNewSize=357564416 
-XX:MinHeapDeltaBytes=524288 -XX:NewSize=89128960 -XX:OldSize=179306496 
-XX:+UseCompressedClassPointers -XX:+UseCompressedOops 
-XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation 
-XX:+UseParallelGC
like image 194
KevinO Avatar answered Oct 18 '25 10:10

KevinO


The jcmd tool is written in Java, so a JDK is needed.

https://github.com/openjdk/jdk/blob/master/src/jdk.jcmd/share/classes/sun/tools/jcmd/JCmd.java

From JDK 9 or later, you can use jlink to create a custom JDK image that only contains modules needed for the jcmd tool.

$ cd %JAVA_HOME%
$ bin\jlink --module-path jmods --add-modules jdk.jcmd --output c:\custom-jdk
$ cd c:\custom-jdk\bin
$ jcmd 

It's about 40 MB on my machine and it can operate against earlier releases. Not sure how much it helps, but it is the clean way to do it.

like image 41
Kire Haglin Avatar answered Oct 18 '25 10:10

Kire Haglin