1

In Java, you can set a max app heap size by providing an -Xmx argument to JVM. Let's say it's 1GB. I thought that the 1GB is given to you from the time your start your app so the app can create objects in that area. But then I read about the adaptive sizing techniques:

The sizes of the heap, the generations, and the survivor spaces can vary during execution as the JVM attempts to find the optimal performance according to its policies and tunings.

Now, I'm lost. I didn't know that JVM may resize the heap size by default. Could you please explain (or provide links to helpful resources that may cover it) how does JVM resize heaps during execution?

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
Tony
  • 459
  • 1
  • 5
  • 18

3 Answers3

2

What you are setting is the maximum heap size that the JVM will be allowed to allocated. It usually starts with a smaller size and only grows as needed (when even after garbage-collection just re-using the existing memory is not sufficient), recent JVM versions also give back space to the operating system by shrinking the heap when that seems appropriate (after a period of heavy load during business hours is over for example).

Thilo
  • 257,207
  • 101
  • 511
  • 656
  • Another disadvantage of a small heap is that the amount of garbage reclaimed per unit of GC work will be smaller. – Stephen C Jan 24 '21 at 05:53
  • Yes. Smaller heap = shorter, but more frequent GC. Which one is better overall depends on your application. That's why they give you so many options to tune it. – Thilo Jan 24 '21 at 06:29
  • It is not just the frequency of garbage collections. It is also the amount of useful work that the GC is able to perform ... per unit of resources expended. (For a copying collector, the non-garbage in a "from" space costs a lot more to process than the garbage.) You are actually losing **both** ways if the heap is too small. – Stephen C Jan 24 '21 at 07:11
  • Yes, and there are other dimensions and tradeoffs to consider as well, for example how much GC competes with useful work for CPU or if stop-the-world-pauses are required frequently and how long those take. What works best overall depends on your application. That's why they give so many option to tune it. – Thilo Jan 24 '21 at 07:15
0

It's also worth noting that while the bulk of the JVM's memory is in the heap, there are also many other native data structures and loading mechanisms that are used for the operation of the JVM itself (JIT cache space, classes defined and loaded in bytecode, and so on). So even if you set a 1Gb limit for your JVM process, it will take up less (or more) than that limit on your operating system.

Worth also bearing in mind that the memory reported in the process/mem list is also not going to count (native) libraries loaded in memory shared by multiple processes, or virtual memory which is allocated but not used by the process (yet). If you want to bring all those in you might want to have -XX:+AlwaysPreTouch set.

AlBlue
  • 23,254
  • 14
  • 71
  • 91
0

Of course the re-size can only happen to the "upper-bound" (-Xmx) of your heap, so the max value is still respected. But a garbage collector can make that smaller, yes. As well as it can grow from -Xms.

In general, there are cases when you really want your garbage collector to re-size the heap. kubernetes is such an environment, for example. kubernetes does not have swap, so when you fill up the RAM, pods will start to be killed. Now if your pods have a setting of -Xmx10g and at some point they really used this much, but currently only use 1GB, for kubernetes, they still consume 10GB. To put it simpler, there are 9GB that some pod does not need nor use right now, but java GC will not handle those back.(more details here). This is where re-sizing the heap might come handy.

G1GC always could give memory back to the OS (re-size to a smaller heap), here is an example, but until java-12 and this JEP, it would only very, very rarely do that. Other garbage collector algorithms (like Shenandoah), will give memory back to the OS faster, for example.

While this might be an advantage in some cases, it comes at a price. un-commit the pages (or resize) is not a free process. Then, the heap is not only used for your allocations of new instances, but also for the GC work itself. When G1 has to copy live objects to different regions, it still uses the heap space for copying from region to region. Then there are internal GC structures that can use the heap too, like SATB queues, etc.

Then there is the fact that because some steps in the GC work are concurrent, you need a heap big enough to cover that delta or newly allocated objects while the concurrent phase is in flight. In general, the more heap you have (the more breathing room a GC has), the better your application will behave.

Eugene
  • 117,005
  • 15
  • 201
  • 306