Debugging java out of memory exception

  1. First run the process that needs to be debugged
  2. Run jps to get PIDs of running java processes. On Windows jps did not give me all the PIDs. But this command worked [1]:
    wmic process where "name='java.exe'" get ProcessID, CommandLine
  3. Once you have found the PID of process you need to debug, you can get heap statistics by running jmap -histo:live <PID>

Read http://stackoverflow.com/a/35963059/147530 to understand the nuances esp. if you are getting this error:

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

Real world example:

Needed to debug a service that would cause an OOM exception after running for a while. Wrote following script to periodically make requests to the service (running at localhost:5622) every 10s and print out top 5 entries from `jmap`’s output:

#!/bin/bash

while true; do

    #http://unix.stackexchange.com/questions/196549/hide-curl-output

    curl -s localhost:5622 > /dev/null

    jmap -histo:live $1 | head -n 8

    sleep 10s

done

Save the script as `debug.sh`. Now can run the process and this script to get realtime output of memory usage:

$. debug.sh 76100

where 76100 is the PID of the java service obtained by running `jps`

See http://stackoverflow.com/questions/1087177/what-do-those-strange-class-names-in-a-java-heap-dump-mean to understand jmap’s output. Sample jmap output (truncated to top 5 entries):

num     #instances         #bytes  class name

----------------------------------------------

   1:        171821       14836520  [C

   2:          6296        7004424  [B

   3:            40        5243520  [Lcom.sun.tools.javac.util.SharedNameTable$NameImpl;

   4:        133194        4262208  com.sun.tools.javac.util.SharedNameTable$NameImpl

   5:        170551        4093224  java.lang.String

Troubleshooting:

Well-known file is not secure:

first thing to check is if the process you are debugging is owned by the same user which is used to start jmap.

if that is the case, the next thing to check is if /tmp/hsperfdata_$USER/$PID file is accessible to that user. Check permissions on both the file and the directory.

More details at:

http://blog.tsunanet.net/2010/10/ioexception-well-known-file-is-not.html

Jmap source code:

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/sun/tools/jmap/JMap.java#JMap.attach%28java.lang.String%29

Using Eclipse MAT

Eclipse MAT is by far considered the most comprehensive tool for debugging heap dumps. One tip in case it fails to run on a Mac. Edit /Applications/MemoryAnalyzer.app/Contents/Eclipse/MemoryAnalyzer.ini and add following lines to it replacing paths as necessary:

-vm
/Library/Java/jdk-21.0.1.jdk/Contents/Home/bin

IMPORTANT: there needs to be a line break between -vm and /Library/Java/jdk-21.0.1.jdk/Contents/Home/bin. My complete file looks like following:

-vm
/Library/Java/jdk-21.0.1.jdk/Contents/Home/bin
-startup
../Eclipse/plugins/org.eclipse.equinox.launcher_1.6.600.v20231106-1826.jar
--launcher.library
../Eclipse/plugins/org.eclipse.equinox.launcher.cocoa.macosx.aarch64_1.2.800.v20231003-1442
-vmargs
--add-exports=java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED
-Xmx1024m
-Dorg.eclipse.swt.internal.carbon.smallFonts
-XstartOnFirstThread

Another tip: change the -Xmx setting if you get OOM while opening a heap dump in Eclipse MAT.

Other Useful Commands to debug OOM

check system logs for OOM exceptions

sudo dmesg -T | grep -i 'oom'
This entry was posted in programming, Software and tagged , . Bookmark the permalink.

Leave a comment