简体   繁体   中英

(JVM heap) What are pros and cons of "Thread-local Eden"?

What's the purpose of Thread-local Eden

In all JVM Garbage Collectors that I know about all new objects are allocated inside Thread shared Eden.

  • Parallel GC "stops the world" on every GC task
  • G1 GC "stops the world" on Eden collection and cleanup phase
  • Shenandoah GC doesn't "stops the world", but adds synchronization between write to a object by Java Thread and moving it by GC Thread.

But what if an object was own by Thread? According to Oracle, " most objects are short lived ". Correct me if I'am wrong, but most of them never leaves the Thread (aka are put somewhere that can be accessed by a different Thread). That means JVM synchronizes a lot of objects that don't need it.

What's Thread-local Eden

All objects allocated by Java Thread are allocated in Eden owned by this Thread. All GC tasks on Thread Eden are performed by its owner. Thread can do operation that can potentially make an object visible to other Threads, for example store it to array. But if it does and object is still in Thread Eden, then it needs to move it into shared heap, or check if it will make it visible and act base on that.

Questions:

  • Why no implementation do this?
  • Would it even work or did I miss something?
  • Why is it (if it is) less efficient than normal GC?

Edit

Yes, I didn't know about TLAB-s, thank you. But I'm asking about fully single Threaded memory. Objects in TLAB can be assigned to anything without any action, they are allocated inside shared memory, so they need some sort of Thread synchronization. Objects in Thread-local Eden don't.

Look, this example program won't need any synchronization:

for (int i = 0; i < Integer.MAX_VALUE; i++)
   new Object();

Thread-local Eden can collect all of this garbage. No synchronization on TLAB fill up needed, because we didn't put anything there.

What's Thread-local allocation buffer

Here is a good explanation on Stack Overflow. But in short (too short) it's a changing fragment of Eden dedicated to one Thread, to exclusively cache it.

Your question is based around the assumption “ they are allocated inside shared memory, so they need some sort of thread synchronization ”. But this is not the case (in this absolute form).

The fact that TLABs are part of a shared memory does not imply that you have to pay synchronization costs when you access it. In fact, a large portion of the architectures out there do not even have a different kind of memory that you could place the TLAB in. What makes memory thread-local, is how you use it. CPU caches do already work in favor of thread-local usage. If two threads, running on different cores, work on different objects, ie memory regions, their core-local caches will already work independently.

There are exceptions, architectures with non uniform memory. The JVM developers are aware of this. The ParallelGC supports NUMA architectures since Java 7 , the G1GC supports them since JDK 14 .

So, not only allocations are purely thread-local with a TLAB, the use of the freshly allocated objects is too. As long as they are not shared with other threads, there are no synchronization costs when using them.

The only interactions with other threads happen

  • When the thread actually shares objects, which requires the use of one of the thread safe constructs specified by the JMM.

  • When the TLAB is full and a new one has to be allocated from the Eden space. In the best case, this is just a single atomic pointer update.

  • When no new TLAB could be allocated because the Eden space is exhausted. Then, the Eden space must be expanded or GC has to take place.

When a GC is performed, it is indeed an event affecting all threads. But a thread-local GC as you suggested would require keeping track of all escaping references. Generational garbage collectors are not only built around the hypothesis that most objects die young but also that they will be intensively used whereas old objects may change less likely. That's why changes to the old generation are tracked but young objects are accessed with the least overhead possible.

Most effort nowadays is spent on concurrent garbage collectors. For them, the distinction between thread-local or young generation collection isn't very meaningful. Their impact on all threads (using CPU cores concurrently to the application threads) is the same, regardless of which memory region they process.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM