I have encountered a bug where one of our server applications was using more and more memory every second pretty much and I have managed to filter out a short example that still shows that behavior:
public class TestGetLastModifiedTime {
private static final Path PATH = Paths.get("D:\\test.txt");
private static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(1);
public static void main(String[] args) {
SCHEDULER.scheduleAtFixedRate(() -> getLastModifiedTime(), 0, 1, TimeUnit.SECONDS);
}
private static void getLastModifiedTime() {
try {
FileTime lastModifiedTime = Files.getLastModifiedTime(PATH);
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
}
Running on Windows 8.1 and Java 8u20.
Via VisualVM I have observed that the maximum heap size does not grow and that the heap itself keeps increasing. Simultaneously I observe in Windows Task Manager that the spawned java.exe process keeps using (reserving) more memory every second.
The interesting part is that when I Perform GC from within VisualVM, all the used heap memory gets reset to practically zero and the used memory of the java.exe process does not shrink, as expected, as it is considered reserved.
However, after the GC has been done, then the memory usage still increases every second, while now there is surely enough free heap space.
The Metaspace is also unaffected.
To me this really smells and looks like the JVM has a memory leak.
Can anyone help me out and explain what is going on here?
I do not consider it as leak for following reasons:
gc
, the memory usage falls back to default. This is not how a leak works. When there is leak, those objects are strongly reachable and even after repetitive garbage collections, the heap size doesn't significantly decrease.java -Xmx20M TestGetLastModifiedTime
ran perfectly fine for 10 mins before I killed the process. If there was a leak, it would ultimately throw OutOfMemoryError
or have too many repetitive gc'sFiles.getLastModifiedTime(PATH)
, ExecutorService
internally would creating small utility objects here and there. So it looks perfectly fine to me.The behavior on my machine:
Of the point, that the Windows manager is showing higher heap usage. It is quite possible. JVM can reserve space if needed. It might be certainly ok with increasing the heap utilization than undergoing gc
. Which perfectly makes sense (Why would you undergo austerity when you are rich?).
That is why tools like observing Windows Manager/free -m
etc do not rightly give observation on whats happening internally. To get quick estimates, you might want to do:
jstat -gccapacity 9043 | tail -n 1 | awk '{ print $4, $5, $6, $10 }' | python -c "import sys; nums = [x.split(' ') for x in sys.stdin.readlines()]; print(str(sum([float(x) for x in nums[0]]) / 1024.0) + ' mb');"
# change the pid from 9043 to your jvm process id.
#jvm process id can be known by running `jcmd` command (available as part of jdk)
Which still gives you a better estimate than free -m
/ Windows Manager
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With