Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Debugging memory problems in java - understanding freeMemory

I have an application that causes an OutOfMemoryError, so I try to debug it using Runtime.getRuntime().freeMemory(). Here is what I get:

freeMemory=48792216
 ## Reading real sentences file...map size=4709. freeMemory=57056656
 ## Reading full sentences file...map size=28360. freeMemory=42028760
freeMemory=42028760
 ## Reading suffix array files of main corpus ...array size=513762 freeMemory=90063112
 ## Reading reverse suffix array files... array size=513762. freeMemory=64449240

I try to understand the behaviour of freeMemory. It starts with 48 MB, then - after I read a large file - it jumps UP to 57 MB, then down again to 42 MB, then - after I read a very large file (513762 elements) it jumps UP to 90 MB, then down again to 64 MB.

What happens here? How can I make sense of these numbers?

like image 555
Erel Segal-Halevi Avatar asked Dec 04 '22 07:12

Erel Segal-Halevi


1 Answers

Java memory is a bit tricky. Your program runs inside the JVM, the JVM runs inside the OS, the OS uses your computer resources. When your program needs memory, the JVM will see if it has already requested to the OS some memory that is currently unused, if there isn't enough memory, the JVM will ask the OS and, if possible, obtain some memory.

From time to time, the JVM will look around for memory that is not used anymore, and will free it. Depending on a (huge) number of factors, the JVM can also give that memory back to the OS, so that other programs can use it.

This mean that, at any given moment, you have a certain quantity of memory the JVM has obtained from the OS, and a certain amount the JVM is currently using.

At any given point, the JVM may refuse to acquire more memory, because it has been instructed to do so, or the OS may deny the JVM to access to more memory, either because again instructed to do so, or simply because there is no more free RAM.

When you run your program on your computer, you are probably not giving any limit to the JVM, so you can use plenty of RAM. When running on google apps, there could be some limits imposed to the JVM by google operators, so that available memory may be less.

Runtime.freeMemory will tell you how much of the RAM the JVM has obtained from the OS is currently free.

When you allocate a big object, say one MB, the JVM may require more RAM to the OS, say 5 MB, resulting in freeMemory be 4 MB more than before, which is counterintuitive. Allocating another MB will probably shrink free memory as expected, but later the JVM could decide to release some memory to the OS, and freeMemory will shrink again with no apparent reason.

Using totalMemory and maxMemory in combination with freeMemory you can have a better insight of your current RAM limits and consumption.

To understand why you are consuming more RAM than you would expect, you should use a memory profiler. A simple but effective one is packaged with VisualVM, a tool usually already installed with the JDK. There you'll be able to see what is using RAM in your program and why that memory cannot be reclaimed by the JVM.

(Note, the memory system of the JVM is by far more complicated than this, but I hope that this simplification can help you understand more than a complete and complicated picture.)

like image 110
Simone Gianni Avatar answered Dec 06 '22 10:12

Simone Gianni