How to get Java Heap Dump from a Kubernetes Pod using jmap? - java

I was following the steps mentioned here How to get a heap dump from Kubernetes k8s pod?
I'm able to get the the process id using top command inside the pod. However, when I run jmap I get this:
~ $ jmap
sh: jmap: not found
I access the pod with this command: kubectl exec -it -- sh
I also tried this command:
kubectl exec -it <pod> -- jmap -dump:live,format=b,file=heapdump.bin 1
But I was getting:
OCI runtime exec failed: exec failed: container_linux.go:349: starting container process caused "exec: \"jmap\": executable file not found in $PATH": unknown command terminated with exit code 126
Is there any other way to get the java heap dump from the pod?

Normally containers are limited on the tools available(like you get 'more', but you don't get 'less'), so the tools available for you depends on your container.
The 2 tools that are used to get a heap dump are jmap and jcmd, check if you got jcmd in the container.
https://www.adam-bien.com/roller/abien/entry/taking_a_heap_dump_with
If not, I recommend to put the java app in a container that has either jmap or jcmd and then run it; even if the container is "heavier" that won't affect the java app nor the heap dump so it will be the same.
If that's not an option, maybe this will be
https://techblog.topdesk.com/coding/extracting-a-heap-dump-from-a-running-openj9-java-process-in-kubernetes/
(not mine).

Related

Why is jstack unable to open socket file when trying to generate a thread dump?

I am trying to generate a thread dump of a java process being run on a Linux instance in AWS. I am using the jstack command on OpenJDK version 1.8.0. The current command I am running is sudo -u <user> jstack -l <java pid> where <user> is the user that started the JVM.
When I run this, I receive the error Unable to open socket file: target process not responding or HotSpot VM not loaded
Potential Problem:
While reading about how jstack works, I noticed that jstack is supposed to generate a socket file /tmp/.java_pidXXX in order to attach to the process. This file is not generated.
My potential solution is that if I can get the socket file to generate, hopefully jstack will be able to run properly.
I am unsure why this error is occurring, but my only idea is that this could this be some kind of permissions error to create files in the /tmp directory. I tried testing my permissions by creating text files in the /tmp directory and I was able to create text files.
How can I get this socket file to generate? Any potential solutions would be greatly appreciated.
Edit
Here I have added the command that was used to create the JVM. The command used to get this command was ps -aux | grep java
java -server -Xmx8192m -XX:+HeapDumpOnOutOfMemoryError ->XX:HeapDumpPath="/tmp" -XX:MaxPermSize=256M -Djava.awt.headless=true ->Dsling.run.modes=dynamicmedia_scene7,,
<instance_name>,samplecontent,crx3,crx3ta>r -Djava.locale.providers=CLDR,JRE,SPI -jar crx-quickstart/app/cq-?>quickstart-6.5.0-standalone-quickstart.jar start -c crx-quickstart -i >launchpad -p 4502 -Dsling.properties=conf/sling.properties
Solution:
An update for anyone who comes across this in the future. I found a solution that worked for me by changing the command that I was using to initially start the JVM. I added the flag -XX:+StartAttachListener which forces the process to generate the /tmp/.java_pidXXX socket file during the booting of the JVM.
Other tips I came across in my journey to finding this solution:
Make sure the user executing the jstack command is the same user that who ran the process that you are trying to take the thread dump of.
Also, make sure the socket file /tmp/.java_pidXXX is not being automatically cleaned up by any background cleanup processes in the /tmp directory.

Execute KILL command from JAVA_OPTS using -XX:OnOutOfMemoryError

I am trying to execute kill command on OnOutOfMemoryError for a SpringBoot application.
Below is the .conf file having command.
JAVA_OPTS="-Xmx512M -XX:OnOutOfMemoryError=\"kill $(lsof -t -i:8080)\""
If I run Spring boot application as "java -jar" with Java Hostspot VM commands it works fine, but while running as Linux systemd service, application is not getting killed.
Exception : "Handler dispatch failed; nested exception is java.lang.OutOfMemoryError: Java heap space"
In my scenario, I run an instance of GeoServer using tomcat with a container in the docker swarm.
I expect swarm to recreate the container after any problem with this instance, but after an OutOfMemory error, the container will never be restarted because the JVM is still running, although the application no longer responds.
For this case, I use OnOutOfMemoryError and the container is eliminated after this type of error, so that the swarm can recreate it.
Tomcat environment to set the JVM parameters.
CATALINA_OPTS="-XX:OnOutOfMemoryError=\"kill -9 %p\"
-Djava.awt.headless=true \
-Dfile.encoding=UTF-8 -server \
-Xms1024m -Xmx3072m -Xss1024k -XX:NewSize=768m \
-XX:+UseParallelGC -XX:MaxGCPauseMillis=500"
You can try to adapt it to your use.
Importantly, i use these software:
Tomcat 9
OpenJDK-11
GeoServer 2.16.x
Debian GNU/Linux 10 (buster)
Docs for consult JVM openJDK-11 configuration options: https://manpages.debian.org/testing/openjdk-11-jre-headless/java.1.en.html

Running jcmd using JDK-11 on JDK-8 java process not running successfully

I am trying to monitor native memory of tomcat using jcmd but getting following exception:
Command: jcmd 14533<pid of tomcat> VM.native_memory summary
I have installed 2 jdk's jdk-11 AND jdk-8.
Tomcat is running by jdk-8 and jcmd used jdk-11 then i got following exception:
com.sun.tools.attach.AttachNotSupportedException: Unable to open socket file /proc/31752/root/tmp/.java_pid31752: target process 31752 doesn't respond within 10500ms or HotSpot VM not loaded
at jdk.attach/sun.tools.attach.VirtualMachineImpl.<init>(VirtualMachineImpl.java:100)
at jdk.attach/sun.tools.attach.AttachProviderImpl.attachVirtualMachine(AttachProviderImpl.java:58)
at jdk.attach/com.sun.tools.attach.VirtualMachine.attach(VirtualMachine.java:207)
at jdk.jcmd/sun.tools.jcmd.JCmd.executeCommandForPid(JCmd.java:114)
at jdk.jcmd/sun.tools.jcmd.JCmd.main(JCmd.java:98)
I attched -XX:+StartAttachListener with java process but it didn't work.
It can be a user permission issue: jmap has to be run with the same user as the java process. e.g. if the owner is usera and this is running in a docker contained execute jmap as user usera
docker exec --user usera -it container_id jmap -dump:format=b,file=/home/usera/memorydump.bin 1
If you are running tomcat as a service on linux check following config in unit file i.e. tomcat.service
PrivateTmp=yes, should be removed. As PrivateTmp=yes create private /tmp folder which is not accessible by tool
If you have ProtectSystem=strict, add ReadWritePaths=/tmp/
Go through man page for systemd unit file config

analysis of a java process "not responding"?

My java process stopped responding. I tried to jstack but failed with below error.
21039: Unable to open socket file: target process not responding or HotSpot VM not loaded
The -F option can be used when the target process is not responding
Then I used -F option, but "No deadlocks found."
Other info:
java version: java version
jmap: jmap
jstat: jstat
jinfo: jinfo
Can anyone help have a look and share some links on troubleshooting this kind of java "not responding" issue?
Possible reasons of Unable to open socket file problem:
The target PID is not a HotSpot JVM process.
This is obviously not your case, since jinfo PID works fine.
JVM is started with -XX:+DisableAttachMechanism option.
This can be also verified by jinfo PID.
Attach socket /tmp/.java_pidNNN has been deleted.
There is a common practice to clean /tmp automatically with some scheduled script. In this case you should configure the cleanup software not to delete .java_pid* files.
How to check: run lsof -p PID | grep java_pid
If it lists a socket file, but the file does not exist, then this is exactly the described problem.
Credentials of the current user (euid/egid) do not match the owner of the attach socket. Make sure you run jstack by the same user as JVM. Attach won't work if you run jstack by a different user, even if this user is root.
/tmp directory of the target process is not the same as /tmp of your shell. This may happen in the following cases:
JVM is started in a different mount namespace. Typically this happens when JVM runs in a Docker container. Running jstack from within the same container will help.
JVM is started in chroot environment. For example, LXC containers may use chroot.
How to check: run readlink -f /proc/PID/root/tmp to see if it points to /tmp or to some other directory.
Current working directory of the target JVM belongs to a file system that does not allow to change permissions. CIFS and DrvFs (WSL) are examples of such file systems.
How to check: run umask 077; touch /proc/PID/cwd/somefile.tmp, then verify that file owner is yourself, and file permissions are 600.
JVM is busy and cannot reach a safepoint. For instance, JVM is in the middle of long-running garbage collection.
How to check: run kill -3 PID. JVM should print a thread dump and heap info in its console. If JVM does not dump anything, but the process consumes almost 100% CPU or shows high I/O utilization, then this looks like the described problem.
JVM process is suspended.
How to check: run ps PID. The STAT column of alive JVM process should be Sl.
More about the internals of jstack.
There is also jattach project which is a better alternative to jstack / jmap. It can automatically handle credentials issue, it works with Docker containers, supports chroot'ed JVMs and handles uncommon file systems.

Running jmap getting Unable to open socket file

I had to run jmap in order to take heap dump of my process. but jvm returned:
Unable to open socket file: target process not responding or HotSpot VM not loaded
The -F option can be used when the target process is not responding
So I used the -F:
./jmap -F -dump:format=b,file=heap.bin 10330
Attaching to process ID 10331, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 24.51-b03
Dumping heap to heap.bin ...
Using -F is allright for taking heap dump?
I am waiting 20 minutes and not finished yet. Any ideas why?
jmap vs. jmap -F, as well as jstack vs. jstack -F use completely different mechanisms to communcate with the target JVM.
jmap / jstack
When run without -F these tools use Dynamic Attach Mechanism. This works as follows.
Before connecting to Java process 1234, jmap creates a file .attach_pid1234 at the working directory of the target process or at /tmp.
Then jmap sends SIGQUIT to the target process. When JVM catches the signal and finds .attach_pid1234, it starts AttachListener thread.
AttachListener thread creates UNIX domain socket /tmp/.java_pid1234 to listen to commands from external tools.
For security reasons when a connection (from jmap) is accepted, JVM verifies that credentials of the socket peer are equal to euid and egid of JVM process. That's why jmap will not work if run by different user (even by root).
jmap connects to the socket, and sends dumpheap command.
This command is read and executed by AttachListener thread of the JVM. All output is sent back to the socket. Since the heap dump is made in-process directly by JVM, the operation is really fast. However, JVM can do this only at safepoints. If a safepoint cannot be reached (e.g. the process is hung, not responding, or a long GC is in progress), jmap will timeout and fail.
Let's summarize the benefits and the drawbacks of Dynamic Attach.
Pros.
Heap dump and other operations are run collaboratively by JVM at the maximum speed.
You can use any version of jmap or jstack to connect to any other version of JVM.
Cons.
The tool should be run by the same user (euid/egid) as the target JVM.
Can be used only on live and healthy JVM.
Will not work if the target JVM is started with -XX:+DisableAttachMechanism.
jmap -F / jstack -F
When run with -F the tools switch to special mode that features HotSpot Serviceability Agent. In this mode the target process is frozen; the tools read its memory via OS debugging facilities, namely, ptrace on Linux.
jmap -F invokes PTRACE_ATTACH on the target JVM. The target process is unconditionally suspended in response to SIGSTOP signal.
The tool reads JVM memory using PTRACE_PEEKDATA. ptrace can read only one word at a time, so too many calls required to read the large heap of the target process. This is very and very slow.
The tool reconstructs JVM internal structures based on the knowledge of the particular JVM version. Since different versions of JVM have different memory layout, -F mode works only if jmap comes from the same JDK as the target Java process.
The tool creates heap dump itself and then resumes the target process.
Pros.
No cooperation from target JVM is required. Can be used even on a hung process.
ptrace works whenever OS-level privileges are enough. E.g. root can dump processes of all other users.
Cons.
Very slow for large heaps.
The tool and the target process should be from the same version of JDK.
The safepoint is not guaranteed when the tool attaches in forced mode. Though jmap tries to handle all special cases, sometimes it may happen that target JVM is not in a consistent state.
Note
There is a faster way to take heap dumps in forced mode. First, create a coredump with gcore, then run jmap over the generated core file. See the related question.
I just found that jmap (and presumably jvisualvm when using it to generate a heap dump) enforces that the user running jmap must be the same user running the process attempting to be dumped.
in my case the jvm i want a heap dump for is being run by linux user "jboss". so where sudo jmap -dump:file.bin <pid> was reporting "Unable to open socket:", i was able to grab my heap dump using:
sudo -u jboss jmap -dump:file.bin <pid>
If your application is runing as a systemd service.You should open service file that under /usr/lib/systemd/system/ and named by your service name. Then check whether privateTmp attribute is true.
If it is true,you shoud change it to false,then refresh service by command as follow:
systemctl daemon-reload
systemctl restart [servicename]
If you want runing jmap/jcmd before restart, you can make use of the execStop script in the service file. Just put command in it and to execute systemctl stop [service name]
Just like ben_wing said, you can run with:
sudo -u jboss-as jmap -dump:file.bin <pid>
(in my case the user is jboss-as, but yours could be jboss or some other.)
But it was not enough, because it asked me for a password ([sudo] password for ec2-user:), although I could run sudo without prompting me for a password with other commands.
I found the solution here, and I just needed to add another sudo first:
sudo sudo -u jboss-as jmap -dump:file.bin <pid>
It works with other commands like jcmd and jinfo too.
It's usually solved with -F.
As stated in the message:
The -F option can be used when the target process is not responding
I encountered a situation where the full GC made it impossible to execute the command.

Categories

Resources