如何在没有JDK的情况下运行jcmd?

时间:2017-04-26 20:56:16

标签: java jmap

我正在尝试弄清楚如何在安装在客户端站点的Windows服务器上删除jcmd.exe,以便我们可以解决堆和线程问题。真的不想安装完整的JDK,因为它会使环境变得复杂。

jcmd.exe肯定希望JDK中的某些组件运行,但我无法确定哪些组件。如果我可以将它解压缩到一个小的集合,我们解压缩到一个文件夹,使用它来捕获数据,然后销毁,这将是完美的。

有人知道jcmd需要运行什么JDK组件吗?

4 个答案:

答案 0 :(得分:1)

快速检查jcmd.exe显示:

    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)

因此,似乎msvcr100.dll和jli.dll将是JDK中唯一必需的组件。一个超级快速的测试似乎表明这三个文件就足够了,但我承认我的测试情况可能并不完美。

编辑:经过进一步检查,这是我发现的最低配置。可以稍微修改目录结构并设置诸如CLASSPATH,JAVA_HOME和PATH之类的东西。我没有探索所有的排列。

.:
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*

我还留下了COPYRIGHT和LICENSE文件,因为我觉得它们很重要。

测试:

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

答案 1 :(得分:1)

jcmd工具是用Java编写的,因此需要JDK。

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

在JDK 9或更高版本中,您可以使用jlink创建一个自定义JDK映像,该映像仅包含jcmd工具所需的模块。

npm install @react-native-community/masked-view

我的计算机上大约有40 MB,可以在较早的版本上运行。不确定它有多大帮助,但这是一种干净的方法。

答案 2 :(得分:1)

这是最小的基于 debian 的 docker 镜像,jcmd 大约 114MB

Dockerfile

FROM adoptopenjdk/openjdk11-openj9:slim as base
ENV    JCMD=/tmp/jcmd
RUN  jlink --module-path jmods --add-modules jdk.jcmd --output ${JCMD}

FROM debian:stretch-slim
COPY --from=base /tmp/jcmd /tmp/jcmd
ENV PATH="/tmp/jcmd/bin:${PATH}"

答案 3 :(得分:0)

我也在寻找一种在JRE上运行jcmd的方法(在生产中)。 我无法使用@KevinO的其他现有答案,因为我正在K8S上运行,并且我的docker映像基于Alpine Linux。

最终,我最终将最小的工件从JDK复制到docker映像中,并且能够运行jcmd并启动Flight Recorder。 我正在使用Azul JRE zulu11.41.24-sa-jre11.0.8-linux_musl_x64。

这是对我有用的东西(来自我的dockerfile的片段):

RUN  tar zxf /tmp/${JDK}.tar.gz -C /tmp && \
        mkdir -p /jcmd && \
        mkdir -p /jcmd/bin && \
        mkdir -p /jcmd/lib && \
        cp /tmp/${JDK}/bin/jcmd /jcmd/bin/jcmd && \
        cp -r /tmp/${JDK}/lib/libattach.so /tmp/${JDK}/lib/jvm.cfg /tmp/${JDK}/lib/libjava.so /tmp/${JDK}/lib/libjimage.so /tmp/${JDK}/lib/libnet.so /tmp/${JDK}/lib/libnio.so /tmp/${JDK}/lib/libverify.so /tmp/${JDK}/lib/libzip.so /tmp/${JDK}/lib/modules /tmp/${JDK}/lib/server /tmp/${JDK}/lib/jli /jcmd/lib && \
        rm -rf /tmp/${JDK}