How to Deal With Non-heap or Native Memory Leak

when question occur out of heap


This week, I meet two very strange memory problems. Althought they are in different system, they have the same appearance —– Java process use much more memory over that JVM option setted.(e.g. Jvm option use 1.5G, but in top command, java consume 2.9G memory).

direct buffer memory


First system was a data-transfer one. It uses Netty heavily. When get the Heap dump we see many DirectByteBuffer objects, it’s one of signals that we have direct buffer memory problem…then we use java.nio.Bits(see this) to confirm that direct buffer memory increase quickly when many request came.

At last, we found that netty sender product much requst that over receiver’s ability. So, we recheck our netty configuaration, and set WATER_MARK option and check channel.isWritable before write data to confirm that Netty has avalible to handle that request, if not we will try it later. Then direct buffer memory is under our control.

native memory


The other system was a Lib-scan one. It will scan many .jar file every day.

At first, we try to dump heap many times, but we can not found any footmark in heap dump.

So, we change tool and use pmap -x [pid] and cat /proc/[pid]/smaps to see java memory usage.

First, we see find many big anon blocks using 65500+ memory, like this..

00007f8b00000000   65512   40148   40148 rwx--    [ anon ]
00007f8b03ffa000      24       0       0 -----    [ anon ]
00007f8b04000000   65520   59816   59816 rwx--    [ anon ]
00007f8b07ffc000      16       0       0 -----    [ anon ]

Then we using gdb to dump the content of these blocks

gdp -pid [pid]

dump memory mem.bin 0x00007f8b00000000 0x00007f8b00000000+65512

Then let it visuable

cat mem.bin | strings

It’s suprise that the block content is MANIFEST.MD file.. at this time, we start to suspect jar..

pmap -x [pid] | grep '.jar' | sort -k6 | uniq -c

After do some statistics, we found that many scanned jar file using memory more then once and never give back it…It’s the problem.

Then open JVM code — jdk/src/share/native/java/util/zip/zip_util.c and ZipFile.c will found ZipFile/JarFile will use mmap and only free then when close() be called..

So, after recheck and fix unclosed ZipFile/JarFile.. The problem was solved.

UPDATE: except un-close Jar file, before jdk1.7 URLClassLoader close JarFile lazy also lead mmap leak… we can use 1.7+ or hack it like this http://snipplr.com/view/24224/class-loader-which-close-opened-jar-files/ or try System.gc

UPDATE: the other accessible way may be let JarFile/ZipFile doesn’t use mmap…we can use jvm opt -Dsun.zip.disableMemoryMapping to disable it.http://www.oracle.com/us/technologies/java/overview-156328.html

Summary


Using heap dump, we can find java heap problem, but Java and Java-Libary also have chance to make non-heap memory leak.

When use nio-libary, we must take care the direct memory usage, using nio libary carefully, and should better let java.nio.Bits be monited(also this way is trick.)

In addition to nio problem, mis-used JNI api also lead the non-heap memory leak, too. We should try pmap or /proc/[pid]/smaps to found which jar/lib/stack/file might using much memory..then use gdb to watch content of blocks to help our analysis.

jvm

Comments