Nathan
Nathan

Reputation: 8981

How to optimize the unused space in the Java heap

Do not take my word on this. I am just repeating what I have pieced together from different sources. HotSpot JVM uses Thread Local Allocation Buffers (TLABs). TLABs can be synchronized or not. Most of the time the TLABs are not synchronized and hence a thread can allocate very quickly. There are a large number of these TLABs so that the active threads get their own TLABs. The less active threads share a synchronized TLAB. When a thread exhausts its TLAB, then it gets another TLAB from a pool. When the pool runs out of TLABs, then Young GC is triggered or needed.

When the pool runs out of TLABs, there are still going to be TLABs with space left in them. This "unused space" adds up and is significant. One can see this space because GC is triggered before the reserved heap size or the max heap size is reached. Thus, the heap is effectively 10-30% smaller. At least that is my guess from looking at heap usage graphs.

How do I tune the JVM to reduce the unused space?

Upvotes: 5

Views: 459

Answers (3)

stelios.anastasakis
stelios.anastasakis

Reputation: 1206

The allocation of TLABs when there is not enough space has a different algorithm but generally what you say about the free space is right.

The question now is how can you be sure that the default TLAB config is not right for you? You need to start by getting some logs by using -XX:+PrintTLAB and if you see that the space that is not used is too much then you need to try to increase/reduce the TLAB size or change -XX:TLABWasteTargetPercent or -XX:TLABWasteIncrement as people said.

This is an article I find useful when I go through TLABs: https://alidg.me/blog/2019/6/21/tlab-jvm

Upvotes: 0

Eugene
Eugene

Reputation: 121078

You are correct that once there are no TLABs, there will be a young generation collection and they will be cleaned.

I can't tell much, but there is ResizeTLAB that allows for the JVM to resize it based on allocations stats I guess, eden size, etc. There's also a flag called TLABWasteTargetPercent (by default it is 1%). When the current TLAB can not fit one more object, JVM has to decide what to do : allocate directly to the heap, or allocate a new TLAB.

If this objects size is bigger than 1% of the current TLAB size it is allocated directly; otherwise the current TLAB is retired.

So let's say current size of the TLAB (TLABSize, by default it is zero, meaning it will be adaptive) is 100 bytes (all numbers are theoretical), 1% of that is 1 byte - that's the TLABWasteTargetPercent. Currently your TLAB is filled with 98 bytes and your object that you want to allocate is 3 bytes. It will not fit in this TLAB and at the same time it is bigger than 1 byte threshold => it is allocated directly on the heap.

The other way around is that your TLAB is full with 99.7 bytes and you try to allocate a 1/2 byte object - it will not fit; but it is smaller than 1 byte; thus this TLAB is committed and a new one is given to you.

As far as I understand, there is one more parameter called TLABWasteIncrement - when you fail to allocate in the TLAB (and allocate directly in the heap) - so that this story would not happen forever, the TLABWasteTargetPercent is increased by this value (default of 4%) increasing the chances of retiring this TLAB.

There is also TLABAllocationWeight and TLABRefillWasteFraction - will probably update this post a bit later with them

Upvotes: 2

TwoThe
TwoThe

Reputation: 14309

You can tweak that setting with the command-line option -XX:TLABSize

However as with most of these "deep down and dirty" settings, you should be very careful when changing those and monitor the effect of your changes closely.

Upvotes: 2

Related Questions