“This is the 18th day of my participation in the August Gwen Challenge.
🔉 introduction
Yesterday said the HotSpot algorithm details of the implementation, algorithm algorithm, efficiency first, to ensure the efficient operation of virtual machines, but did not finish, today complete.
📇 Memory set and card table
Before I talk about memory sets, I don’t know if you remember when I talked about cross-generational references to objects, but if you don’t remember, you can go through the portal and take a look. The Remembered Set prevents us from putting the entire old age into the GCRoots for scanning. This is actually a problem not only for our generations, but for all of our garbage collectors that deal with partial behavior. Therefore, it is necessary to further understand and learn the working principle and mode of memory set.
The essence of a memory set is a data structure. What kind of data structure? A collection of Pointers that record Pointers from a non-collection region to a collection region is simplest represented by a collection of objects referenced across generations in a non-collection region.
This way of record high cost, in fact, the collector only need through memory set to determine whether there is a piece of the collection area collection area of the reference pointer is ok, don’t need to understand the actual details of intergenerational references, we can choose the more rough granularity on implementation in order to save memory storage and maintenance costs, the following is a record accuracy of reference:
- Word length accuracy: Each record is accurate to a word length that contains cross-generation Pointers
- Object precision: Each record is accurate to one object. Object that contains field records across generations
- Card precision: Each record is accurate to a memory region whose objects contain cross-generation Pointers
🎴 card table
Different from the memory set mentioned above, the memory set is an abstract data structure, which only defines the behavior intention of the memory set, but does not define the concrete implementation, while the card table defines the concrete implementation of the memory set. It defines the record precision of memory set and the mapping relation of heap memory.
How does the card watch work? Do we associate tables with databases? Each element of the byte array Card_Table corresponds to a fixed size block of the memory area it identifies. Such a block is also called a Card Page. The size of the Card Page is 2 to the NTH power of bytes. The size of our HotSpot card page is two to the ninth power of 512 bytes, so if the starting address is 0 then 0, then 1 for 512 (base 10) and 2 for 1024 (base 10). Figure is as follows:
When a card page has one (or more) object field containing cross-generation Pointers, identify the array element value of the corresponding card table as 1, then the element is called dirty. When garbage collection occurs, we just need to find these dirty elements and force them to tell the corresponding memory cross-generation reference pointer. Send them to GCRoots for testing.
🎴 Card table maintenance
Next, how is the card table maintained? Who gets it dirty? When does it get dirty? When to get dirty is easy. Whenever an object in another generation region references an object in that region, the corresponding card table element should get dirty. The question is how to get dirty? How do I update the card table the moment an object is assigned?
It’s time to torture the virtual machine and HotSpot maintains Write barriers. Before a reference is assigned, the object should make a cut and insert a write barrier. After the assignment, the object should insert a write barrier and update the card table in the write barrier so that both before and after the assignment are within the write barrier.
After application write barriers, virtual machine operation to generate the corresponding instructions for all assignment, update the card table as long as the operation, will generate additional costs, also will encounter “false sharing problem, because modern CPU Cache is a Cache Line (Cache Line) as the unit of storage, the high concurrency scenarios, when multithreaded modify variables, If these variables are all on the same cache row, the same cache will be written to when the card table is updated, resulting in performance degradation.
After JDK7, we can use -xx :+UseCondCardMark to enable the update condition of the card table, and mark the card table elements as dirty only if they are not marked, thus avoiding the problem of fake sharing.
📝 digression
A man may do what he will, but he cannot get what he wants-Schopenhauer.
I was inspired by that. These words have always been a comfort to me in times of suffering, my own or others’, and a wellspring of endless forgiveness. Fortunately, this realization not only alleviates feelings of impotence, it also prevents us from being too hard on ourselves and others.