Java as an object-oriented, cross-platform language, its objects, memory and other knowledge has been more difficult, so even a Beginner of Java, there must be more or less some understanding of the JVM. It can be said that the relevant knowledge about the JVM, is basically every Java developer must learn the knowledge, is also the interview of the time of the knowledge.
In the MEMORY structure of the JVM, the two common areas are heap memory and stack memory (if not referred to, this article refers to the virtual machine stack), about the difference between heap and stack, many developers are also familiar with, there are many books, or articles on the Internet are probably like this:
1. The heap is the memory area shared by threads, and the stack is the memory area exclusively shared by threads.
2. The heap mainly stores object instances, and the stack mainly stores various basic data types and references to objects.
However, I am responsible to inform you that neither conclusion is entirely correct.
This article starts with a look at why I say that “the heap is the memory area shared by threads, and the stack is the memory area exclusively shared by threads.” This is not entirely true! ? You can read about the JVM memory structure VS The Java Memory model VS the Java Object Model. Such as articles.
Before I start, let me ask a seemingly unrelated question: How does the memory allocation process for Java objects remain thread-safe?
How is the memory allocation process for Java objects thread-safe?
As we know, Java is an object-oriented language, and everything we use in Java needs to be created, and there are many ways to create an object in Java, but in any case, memory needs to be allocated during the creation of an object.
In the memory allocation process of an object, the reference of the object refers to this memory region, and then the initialization operation is carried out.
However, because the heap is globally shared, it is possible for more than one thread to claim space on the heap at the same time, so what if, in a concurrent scenario, two threads refer objects to the same memory area in succession?
To solve this concurrency problem, the object memory allocation process must be synchronized. However, we all know that no matter which synchronization scheme is used (in fact, the VIRTUAL machine may use CAS), memory allocation will be affected.
And the allocation of Java objects is a very frequent operation in Java, so people thought of another way to improve the efficiency. Here we focus on a HotSpot virtual machine solution:
Each thread allocates a small chunk of memory in the Java heap in advance, and when it allocates memory to an object, it allocates it directly from its own “private” memory, and allocates new “private” memory when it runs out.
This scheme is known as TLAB Allocation, or Thread Local Allocation Buffer. This part of the Buffer is separated from the heap, but is exclusive to the local thread.
What is a TLAB
TLAB is a dedicated space of the virtual machine in Eden in the heap memory, which is exclusive to threads. TLAB function in the virtual machine start, when the thread is initialized, an TLAB space virtual opportunities for each thread, used only for the current thread, so that each thread has a space alone, if you need to allocate memory, on your own space allocation, so there is no competition, can greatly improve the allocative efficiency.
Notice the above description for “thread only”, “for the current thread only”, and “owned by each thread”?
Therefore, with THE TLAB technology, the heap memory is not completely shared by threads, and there is still some space in the Eden region that is allocated exclusively for threads.
It is worth noting here that we say TLAB is thread exclusive, but only in the “allocation” action is thread exclusive, as for the read, garbage collection and other actions are thread shared. And there is no difference in usage.
This does not mean that the memory in the TLAB area is completely inaccessible to other threads. Other threads can read it, but they cannot allocate memory in the TLAB area.
In addition, after TLAB allocation, object movement and collection are not affected. That is, although objects may be allocated through TLAB at first and stored in Eden, they will still be garbage collected or moved to Survivor Space, Old Gen, etc.
It is also important to note that we say that TLAB is allocated in the Eden region, because the Eden region itself is not very large, and the memory of the TLAB space is very small, occupying only 1% of the total Eden space by default. Therefore, there must be some large objects that cannot be directly allocated in TLAB.
If a large object cannot be allocated in TLAB, the object may be allocated in Eden or old age, but this allocation needs to be controlled synchronously, which is why we often say that small objects are more efficient than large ones.
The problem with TLAB
Although to some extent, TLAB greatly improves the speed of object allocation, but TLAB is not without any problems.
As we said earlier, because the TLAB memory area is not very large, there may often be insufficient situations. Here’s an example from the Actual Java Virtual Machine:
For example, the TLAB space of a thread is 100KB, of which 80KB has been used. When a 30KB object needs to be allocated, it cannot be directly allocated in TLAB. In this case, there are two solutions:
1, if an object needs more space than the size of the remaining space in TLAB, the object is directly allocated in the heap memory.
2. If the space required by an object exceeds the remaining space in TLAB, the current TLAB is abandoned and a new TLAB space is applied for memory allocation again.
There are pros and cons to each of the above two scenarios. If scenario 1 is adopted, there may be an extreme case where only 1KB is left in TLAB, resulting in most of the subsequent objects to be allocated directly in heap memory.
If scheme 2 is adopted, there may be frequent abandonment of TLAB and frequent application for TLAB. As we know, although memory allocation on TLAB is exclusively owned by threads, there may indeed be conflicts in the process of TLAB memory partition from the heap. Therefore, TLAB allocation process actually needs concurrent control. Frequent TLAB assignments lose the meaning of using TLAB.
To solve these two problems, the virtual machine defines a value of refill_waste, which can be translated as “Maximum wasted space.”
When the requested memory allocation is greater than refill_waste, the heap memory will be allocated. If the value is less than the value of refill_WASTE, the current TLAB will be abandoned and a new TLAB will be created for object memory allocation.
In the previous example, the total TLAB space is 100KB, 80KB is used and 20KB is left. If the refill_waste value is set to 25KB, then if the new object’s memory is greater than 25KB, the heap memory will be allocated directly. If the new object’s memory is less than 25KB, the previous TLAB will be abandoned. Reallocate a TLAB space and allocate memory for the new object.
Parameters used by TLAB
The TLAB function is optional. You can specify whether to enable TLAB assignment by setting the -xx :+/ -usetlab parameter.
TLAB default is the 1% of Eden area, can through the options – XX: TLABWasteTargetPercent set TLAB space occupied the percentage of Eden space size.
By default, the space of TLAB is constantly adjusted at runtime to make the system run optimally. If you need to disable automatic TLAB ResizeTLAB, you can use -xx: -Resizetlab to disable it, and -xx: TLABSize to manually specify the TLAB size.
TLAB’s refill_waste can also be adjusted. The default value is 64, which means that about 1/64 of the space size is used as refill_waste. The parameter -xx: TLABRefillWasteFraction is used to adjust it.
If you want to see how TLAB is being used, you can track it with the -xx +PringTLAB parameter.
conclusion
To ensure thread-safe memory Allocation of objects, the HotSpot virtual machine provides a technique called TLAB(Thread Local Allocation Buffer).
During thread initialization, the virtual machine allocates a piece of TLAB space for each thread, which is only used by the current thread. When memory needs to be allocated, it allocates it on its own space, so that there is no competition and the allocation efficiency can be greatly improved.
Therefore, the statement “the heap is a thread shared memory area” is not entirely true, because TLAB is a part of the heap memory, it is read by the thread shared, but in memory allocation, is the thread alone.
TLAB is not really a big space, so large objects may need to be allocated directly in heap memory. Then, the memory allocation step of the object is to try TLAB allocation first. After the space is insufficient, then determine whether to directly enter the old age, and then determine whether to re-eden allocation or allocate in the old age.
Say a few words more
I believe that after reading this article, some may feel that the author is a little too “bite the tongue”, “picky”. There may be some impatient people who read only the beginning and then go straight to the end of the article ready to fight.
Whether you agree with the author or not, it is not entirely true that the heap is an area of memory shared by threads. It doesn’t really matter, but when it comes to heap memory, thread sharing, object memory allocation, you can think of a special TLAB, and that’s it.
Sometimes, the most terrible thing is not that you don’t know, but that you don’t know you don’t know.
Also, TLAB is only an optimization for the HotSpot virtual machine, and there is no provision for TLAB in the Java virtual machine specification. Therefore, this does not mean that all virtual machines have this feature.
This overview is based on the HotSpot virtual machine, and I’m not trying to be “generic”, but because HotSpot is by far the most popular virtual machine, and by default most of our discussions are based on HotSpot.
Ah, every time to write some technical articles, there will be a lot of people spray, spray Angle is also a strange, so had to say a few words to find find fill. Anyway, any kind of discussion is welcome, because you don’t necessarily have a rival.