JCMD, JFR and JMC

There are several ways of getting a Java Flight Recorder (JFR) recording. You can give command line options, or get a JFR recording started ad hoc. The latter is what I will cover here.

JCMD

First question is: Do you have JCMD available? If you do not, you want to get it installed somehow.

Copy tools out of image

If uncertain what is inside the image:

docker run --rm -it bellsoft/liberica-openjdk-debian:23-cds bash

Here, we just copy a JDK out of an image. An alternative would be to explode a distribution, and use that. This feels somewhat easier, making me more confident that the JDK is compatible.

IMAGE=bellsoft/liberica-openjdk-debian:23-cds
docker pull --platform linux/amd64 $IMAGE
docker create  --platform linux/amd64 --name tmp-del $IMAGE
docker cp tmp-del:/usr/lib/jvm/jdk-23-bellsoft-x86_64/ jdk

Then you copy the full jdk into your container:

export POD=$(podhash k8sdebug)
kubectl cp jdk $POD:/tmp/jdk
kubectl exec -it $POD -- bash

Inside the container set the path:

java -version
export JAVA_HOME=/tmp/jdk
export PATH=/tmp/jdk/bin:$PATH
java -version
jcmd
jcmd 7 JFR.start
jcmd 7 JFR.stop
jcmd 7 JFR.dump name=1 filename=/tmp/filename1.jfr

Copy out the image to your local machine:

kubectl cp k8sdebug-$HASH:/tmp/filename1.jfr filename1.jfr

Will probably work best if the same distro.

Jattach

To copy a whole JDK feels both wasteful, and dirty. An alternative is to use the jattach tool (if you trust its origins): https://github.com/jattach/jattach/releases

export POD=$(podhash k8sdebug)
curl -L -o - https://github.com/jattach/jattach/releases/download/v2.2/jattach-linux-x64.tgz|tar -xzf -
kubectl cp jattach $POD:/tmp/jattach

What if you get:

level=error msg="exec failed: unable to start container process: exec: \"tar\": executable file not found in $PATH"

Just pipe it:

cat jattach| kubectl exec -i $(podhash k8sdebug) -- bash -c "cat > /tmp/jattach" 

The commands are then analogous to jcmd from the JDK distribution.

kubectl exec -it $(podhash k8sdebug) -- bash
/tmp/jattach 7 jcmd help
/tmp/jattach 7 jcmd JFR.start
/tmp/jattach 7 jcmd JFR.start
/tmp/jattach 7 jcmd JFR.stop
/tmp/jattach 7 jcmd JFR.dump name=1 filename=$PWD/filename1.jfr

jcmd 7 GC.class_histogram|more

JMC

Java Mission Control (JMC) is a GUI for JFR: https://github.com/openjdk/jmc

Let's get a more representative dump:

  • suspend flux
  • use the image with the "manual" tag
  • run the tests
kubectl create -k ../clusters/kind/apps/k6test/