directory

• Write it first

• Mark-clear algorithm

• Replication algorithm

• Mark-collation algorithm

• Algorithm implementation guarantee on HotSpot

• GC collector

• Memory allocation policy


• Write it first

The JVM garbage collection algorithm, collector and memory allocation strategy together to understand and understanding, I think will help us to deepen the impression, this article I will no longer tell why object to recycle and when to recycle, want to understand relevant knowledge can read my another article JVM how to judge whether the object to be recycled. A few points put together will be a bit too much content, but I made a directory, need to click on the directory jump can be. The JVM pauses all threads of the Java program in order to perform garbage collection. Wait until the garbage collection is complete, then continue running. So minimizing the time spent stopping the world is our primary goal in optimizing the JVM.

• Mark-clear algorithm

First is about tags – clear algorithm, which is the most basic of garbage collection algorithms, we can know, see its name algorithm is divided into two stages, respectively is “mark” and “remove” in two stages, first mark all all need recycled object, after the completion of a tag, unified recycling all the marked object, as to how to achieve the object tag, The details will move to another article on how the JVM determines whether an object should be reclaimed. The collection algorithm mentioned later is based on the idea of this algorithm and its shortcomings are improved.

This algorithm mainly has two deficiencies: the first is the efficiency problem, marking and clearing the efficiency of the two processes are not high; There is also the problem of memory space. After mark clearing, this algorithm will leave a large number of discontinuous memory fragments. These space fragments will lead to an obvious problem that the memory cannot be allocated to larger objects, and the garbage collection will start in advance if there is not enough memory to allocate to objects. As shown in the figure below

• Replication algorithm

So, in order to solve the efficiency problem, there is the replication algorithm, which divides the available memory by capacity into two equally sized pieces, using only one piece at a time. When this memory is used up, it will also live objects are copied to another memory block, and then clear out the used memory space, so that every time is about half of the space in memory, memory allocation when you don’t have to consider memory fragments, such as complicated situation, as long as moves the pointer on the top of the heap, distribution in sequence, a simple and efficient, However, this algorithm sacrifices half of the memory space, as shown below. In fact, if we know the life time of objects, we can find that in fact, most objects will be cleared, the proportion is about 98%, SO we can improve the algorithm, instead of 1:1 space division, Instead, the memory is divided into a large space (often called Eden space) and two small Spaces (often called Survivor space), with a size ratio of 8:1:1. The reason why we need two S Spaces is that we need a space for guarantee. The general process is as follows (detailed allocation strategy will be explained). Each time we clean up, we copy the Eden space and the surviving object of one Survivor space to another Survivor, and then clean up the Survivor space and Eden, wasting only 10% of the memory space each time.

• Mark-collation algorithm

Same, if when object replication algorithm of survival rate is higher, need to be more copy, so that reduces the efficiency, and we also need to use the extra space to guarantee, it is not suitable for use on the old s (generational will further behind, old age is all the object, “don’t want to die” so survival rate is higher). Therefore, according to the characteristics of the old era, the mark-collation algorithm is proposed, but different from the mark-clear algorithm, after marking, it moves the surviving object to one end, and then clears the space beyond the surviving object boundary. The general picture is as follows:

• Algorithm implementation guarantee on HotSpot

We before the GC, certainly need to be effective for determining object survival condition, the method we use is the accessibility analysis, accessibility analysis is a more important part is to find GCRoots, and can generally be GCRoots objects in the virtual machine and the local method stack and method of area, think about it, as big light method area there hundreds of megabytes, We each iterate through all the references, it is obviously not practical nor efficient, in addition, the accessibility analysis of the relations between the reference object in the process of changing is very sensitive, because of the accessibility analysis of work must be in a can ensure the consistency of the snapshot (like the whole system is frozen at a point in time), This also causes GC to stop the world while GC is going on. So we must speed up the reachability analysis to reduce the GC pause time.

In reality, Java virtual machines use exact GC, which means that when the execution system stops, there is no need to have an exhaustive check of all reference locations, but some way to find out where object references are stored. This is done through a set of data structures called OopMap. After the class is loaded, HotSpot calculates what type of data is at what offsets in the object, which JIT compilation drags in, and references those locations in the stack and registers at specific locations, so that GC scans can see this information directly.

GCRoots enumerations can be done quickly with HotSpot, but one issue that stands out is that there are a lot of instructions that can cause the reference relationship to change, or the content of the OopMap to change. If you generate an OopMap for each instruction, the cost of GC space will be high. In fact, not every instruction generates an OopMap. We only record this information at certain locations, which are called safe points. Not all parts of the program can be stopped to start GC, but only when it reaches a safe point. Safety points should not be too small to cause GC wait times to be too long, nor too frequent to cause excessive increase in runtime compliance, so there is a method for determining safety points, but I won’t go into this method, otherwise it will be difficult to finish. All threads run to a safe point pauses there are two kinds of schemes, one is a steal interrupt, which does not require threads execute code cooperate actively, the GC occurs, the first all interrupts all threads, if found to have a thread interrupt place not on the safety point, will restore the thread, causing it to perform to a safe (implementation) virtual machine without this way now. The other is active interrupt, that is, GC does not interrupt the thread directly, but simply sets a flag, each thread executes actively polling this flag, and the thread finds the interrupt flag and suspends itself.

The safety point is a great idea, but there are still some problems that lead to the failure of the safety point, that is, before entering the safety point, the program does not execute, what is the program does not execute, for example, before reaching the safety point, the program occurs in the state of Sleep or Blocked, The thread is unable to respond to interrupt requests from the JVM at this point, so a safe zone is used to address this situation. Can understand it’s actually an extension of the safe point, when the thread to the safe zone, first identify itself into the security area, in that way, when that time, the JVM to initiate the GC, they will take care of thread identify themselves as the security area, when a thread is to leave the safety area, it will check to see if the system has been completed the root node enumeration (or the whole process of GC), If it’s done, the thread continues, otherwise it waits.

• GC collector

Serial collector: The Serial collector is the oldest, most stable, and efficient collector, and may produce a long pause and use only one thread to collect. The new generation and the old use serial recycling; New generation replication algorithm, old age marker – compression; – Garbage collection stops The World

ParNew collector: The ParNew collector is essentially a multithreaded version of the Serial collector. New generation parallel, old age serial; New generation replication algorithm, old age marking – compression

The Parallel collector is similar to the ParNew collector, the Parallel collector focuses on the throughput of the system. You can set parameters to enable the adaptive adjustment policy. The vM collects performance monitoring information based on the current system running status and dynamically adjusts these parameters to provide the most appropriate pause time or maximum throughput. You can also use parameters to control how many milliseconds or percentages GC takes; New generation replication algorithm, old age marking – compression

The Parallel Old Collector: The Parallel Old is an older version of the Parallel Avenge collector that uses multithreading and a “mark-and-collate” algorithm. This collector was only available in JDK 1.6

CMS collector: THE CMS collector is a collector whose goal is to obtain the shortest collection pause time. At present, a large part of Java applications are concentrated on the server side of Internet sites or B/S systems. These applications pay special attention to the response speed of services and hope that the system pause time is the shortest, so as to bring users a better experience. As the name (which includes “Mark Sweep”) suggests, the CMS collector is based on a “mark-sweep” algorithm, which is more complex than the previous collectors. The process is divided into four steps, including:

CMS Initial Mark requires “Stop The World”

CMS Concurrent Mark

Remarking (CMS Remark) requires “Stop The World”

CMS Concurrent sweep

The initial marking and re-marking steps still need to “Stop The World”. Initial marking only marks the objects directly associated with GC Roots, which is very fast. Concurrent marking is the process of GC Roots Tracing, while re-marking is to revise the marking records of those objects whose marks are changed due to the continuous operation of user programs during concurrent marking. The pause time in this phase is generally slightly longer than in the initial tagging phase, but much shorter than in concurrent tagging. Since the collector thread can work with the user thread during the longest concurrent markup and concurrent cleanup, the CMS collector’s memory reclamation process is generally executed concurrently with the user thread. Old collector (New generation using ParNew)

Advantages: Concurrent collection, low pauses

Disadvantages: large amount of space debris, concurrent phases reduce throughput

G1 collector: G1 is one of the most advanced developments in technology and the HotSpot development team has given it the mission to replace the CMS collector released in JDK1.5 in the future. Compared to the CMS collector, the G1 collector has the following features:

Space consolidation, G1 collector uses the tag collation algorithm, does not generate memory space fragmentation. Allocating large objects does not trigger the next GC prematurely because contiguous space cannot be found.

Predictable pauses, this is another big advantage of G1, reduce the pause time is the common concern of G1 and CMS, but G1 in addition to the pursuit of low pause, also can establish predictable pauses model, can let the user specify in a length of N segment within milliseconds, time on garbage collection may not consume more than N milliseconds, This is almost already a feature of the real-time Java (RTSJ) garbage collector.

The garbage collector mentioned above collects the entire Cenozoic or old generation, which is no longer the case with G1. When using the G1 collector, the memory layout of the Java heap is very different from that of the other collectors. It divides the entire Java heap into independent regions of equal size. While the concept of new generation and old generation is retained, the new generation and old generation are no longer physically separated. They are all collections of partial (possibly discontinuous) regions. G1’s Cenozoic collection is similar to ParNew’s. When the Cenozoic occupation reaches a certain proportion, the collection starts. Like CMS, the G1 collector pauses briefly to collect old objects.

• Memory allocation policy

Memory allocation of objects, total overall, is allocated on the heap (but may also be separated after the JIT compiler for scalar type and indirect allocated on the stack) object on the Eden to area of main distribution in Cenozoic, but in particular, if launched the local threads allocated buffer (you can refer to my another article, how to determine whether the object can be recycled). A few cases may also be directly assigned in the old age. However, in most cases, objects are allocated in Eden of the new generation. When Eden does not have enough space to allocate objects, the VIRTUAL machine will initiate a MinorGC. FullGC/MajorGC refers to the old GC, and it can be said that every time a MajorGC occurs, at least one MinorGC occurs. When a large object appears, it can be assigned to an older age. Why? This is because in the new generation, if you encounter large objects with a short lifetime (objects such as very long strings or arrays), memory replication will occur frequently, consuming resources.

It is worth mentioning that virtual machines use the idea of generational collection to manage memory, and naturally need to decide which objects are placed in the new generation and which objects are placed in the old age. To do this, the virtual machine defines an object age counter for each object. If the object still exists after Eden is born and passes the first MinorGC and can be accommodated by Survivor, it will be moved to Survivor space and the object’s age is set to 1. Each time a Survivor passes a MinorGC, the age increases by 1. When the age reaches a certain level, the object is promoted to the older age (15 by default). Of course, it is not necessary to say that objects must reach a certain age to enter the old age. In order to better adapt to the memory status of different programs, the VIRTUAL machine provides that if the sum of all objects of the same age in the Survivor space is greater than half of the Survivor space, objects older than or equal to this age can directly enter the old age. Instead of waiting for a set age threshold.