Sorry if question is already exist, but wasn’t able to find it.
Can you explain the logic of java memory usage.
There are my steps:
- Set xmx4000M
- Run app
- Do stress test
After stress test my app used about 1.4G RAM. But If set xmx300M and did stress test – no performance digression, but app used about 370M (I know that xmx is about heap, gc and other things also need ram). Why java so aggressively reserve ram and can I prevent java to do it but leave high heap size?
Update:
I’m using Java 16 OpenJDK with all default settings except xmx.
PC spec:
i7 10700
16 GB Ram
Advertisement
Answer
Why java so aggressively reserve ram.
GC ergonomics.
-
The JVM will use less time garbage collection if the GC has plenty of free space. So when resizing the heap it tends to determine the heap based on an optimal ratio of used to free space.
-
The JVM is typically reluctant to give memory back to the operating system. It usually only does this after a major GC, and only then if a few major GCs in a row have found that there is too much free space. (Why? Because each heap resize (up or down) entails a full GC, and that is expensive.)
It is not unusual for the heap to grow much larger than the initial size, even though it looks like the heap is bigger than it needs to be. And we also have the fact that an application’s startup behavior is typically rather different to its steady state behavior. (There are lots of JVM and application “warm up” effects.)
Can I prevent java to do it but leave high heap size?
There are some things that you could tweak.
-
There are GC options that will make the GC more willing to give memory back to the OS.
-
There are (I think) GC options that will make the GC less eager to ask the OS for more memory.
But these things impact on (typically) throughput; i.e. they cause your application to spend more time (more CPU cycles) running the garbage collector.
My advice would be to start by reading the Oracle GC Tuning Guide. After reading it, review what your performance goals are, decide on the most appropriate collector, and try the “behavior based tuning” approach. (The idea is to tell the JVM what the goals are, and let it set the low level GC tuning parameters itself to attempt to achieve them.)
Bear in mind that GC tuning is about balancing the costs versus benefits, AND that the optimal settings will vary depending on the application and its (actual) workload.
In your circumstances, I think it is probably NOT worthwhile to tune the GC. You say you have 16GB of RAM. And the app is using only 1.6GB of the 16GB. And this is stress testing … not normal operation for you application.
Now maybe you are optimizing for a production environment with less RAM. But if that is the case, you would be advised to optimize on the production platform itself … or as close to it as you can get.
Also note that optimizing to stop the JVM allocating memory aggressively (up to the -Xmx limit), will probably reduce throughput when your application is under stress.