Today’s sharing started, please give us more advice ~

The Java heap

For most applications, the Java Heap is the largest chunk of memory managed by the Java virtual machine. The Java heap is an area of memory shared by all threads that is created and sized at virtual machine startup. The sole purpose of this memory area is to hold object instances, and almost all object instances are allocated memory here.

According to the Java Virtual Machine specification, the Java heap can be in a physically discontinuous memory space, as long as it is logically contiguous, like our disk space.

Heap memory size is adjustable and can be implemented either as a fixed size or as expandable, although most current virtual machines are implemented as expandable (controlled by -xmx and -xMS).

The Java heap is the area where the Garbage Collection is focused. Objects in the heap are not removed immediately after the method ends, but only at Garbage Collection time, when the Garbage Collection is triggered. This is often referred to as a “GC heap”.

From the point of view of memory collection, the Java heap can be subdivided into: new generation, old generation, and permanent regions (known as meta-spaces after JDK8), since the collector is basically a generational collection algorithm.

Cenozoic and Old age:

If the Java heap is further subdivided, it can be divided into YoungGen and OldGen. By default, the ratio of young generation to old generation is 1:2, -xx: NewRatio=2.

The young generation can be divided into Eden space, Survivor0 space and Survivor1 space (sometimes called FROM zone or TO zone).

In HotSpot, the default ratio of Eden Spaces to Survivor Spaces is 8:1:1 (-xx:SurvivorRatio=8).

  • The young generation is the region where objects are born, grow, and die, where an object is created, applied, and finally collected by the garbage collector to end its life.

  • Older generations of objects with long life cycles are usually Java objects copied from survivor zones. Of course, there are special cases where we know that ordinary objects will be assigned to tLabs; If the object is large, the JVM will try to allocate it directly elsewhere in Eden. If the object is too large to find enough contiguous free space in the new generation, the JVM allocates it directly to the old generation. When GC occurs only in the young generation, the act of reclaiming objects from the young generation is called MinorGc.

  • When GC occurs in an older age, it is called MajorGC or FullGC. In general, MinorGC occurs much more frequently than MajorGC, meaning that garbage collection will occur much less frequently in older generations than in younger ones.

Java objects stored in the JVM can be divided into two classes:

  • One is transient objects with a short lifetime, which can be created and killed very quickly

  • The other class of objects has a very long life cycle and can be consistent with the JVM’s life cycle in some extreme cases

Almost all Java objects are newly created in Eden area, and most of the destruction of Java objects is carried out in the new generation. (If some large objects cannot be stored in Eden area, they will directly enter the old age.) According to the special research of IBM, 80% of objects in the new generation are “dying overnight”.

Note: MinorGC will only trigger when Eden is full and will not trigger when Survivor is full. If the Survivor zone is full, some special rules will be triggered, which makes it possible to promote the older generation directly

You can set the maximum memory size for the new generation using the option “-xmn”.

From the perspective of memory Allocation, the Java heap shared by threads may have multiple Thread private Allocation buffers (TLabs). However, no matter how to partition, it has nothing to do with memory storage, no matter which region, the storage is still the object instance, the purpose of further partition is to better reclaim memory, or faster allocation of memory.

The heap size is set at JVM startup and can be set with the options “-xmx” and “-xms”.

-xMS10M: minimum heap memory/initial memory, equivalent to -xx:InitialHeapSize

-xmx10m: maximum heap memory, equivalent to -xx :MaxHeapSize

The -xms and -xmx parameters are typically set to the same value to improve performance by eliminating the need to re-delimit the heap size after the AVA garbage collection mechanism has cleaned up the heap.

Heap space parameter Settings:

OutOfMemoryError is thrown if there is no memory in the heap to complete the instance allocation and the heap can no longer be expanded (memory size exceeds the maximum memory specified by “-xmx”).

Object allocation

For the new object allocate memory is a very precise and complicated task, the JVM’s designers not only need to consider how to allocate memory, where is the distribution problems, and because the memory allocation algorithm is closely related to the memory recovery algorithm, so you also need to consider the GC to perform after the memory recovery will produce memory fragments in the memory space.

Object allocation process:

  • The object of new is the Garden of Eden, which has a size limit.

  • When Eden fills up, the program needs to create objects again. The JVM’s garbage collector will MinorGC Eden garden, destroy the objects in Eden Garden that are no longer referenced by other objects, and then load new objects into Eden Garden.

  • Then move the remaining objects in Eden to Survivor 0.

  • If garbage collection is triggered again, the last surviving item will be placed in Survivor 0, if not collected, it will be placed in Survivor 1.

  • If the garbage collection is repeated, it will be put back into Survivor 0 and then go to Survivor 1.

  • When can WE go to the nursing home? The maximum number of times (-xx :MaxTenuringThreshold= N) can be set. The default value is 15.

  • In the retirement area, relatively leisurely. When the memory of the endowment area is insufficient, GC: Major GC is triggered again to clean the memory of the endowment area

  • If a Major GC is performed in the endowment area and the object cannot be saved, an OOM exception will be generated.

Object allocation process diagram

Memory allocation strategy:

If the object is still alive after Eden is born and passes the first Minor GC and can be accommodated by Survivor, it is moved to Survivor space and the object age is set to 1. Each time an object survives MinorGC in a survivor zone, its age increases by one year, and when it reaches a certain age (15 by default, which varies from JVM to GC), it is promoted to the old age. The object allocation principle for different age groups is as follows:

  • Eden is assigned priority

  • Large objects are allocated directly to the old generation, and since newly created objects are dead, they may also be recycled quickly, but because the old generation triggers fewer Major GCS than the Minor GC, it may be slower to recycle, so try to avoid too many large objects in your program

  • Long-lived objects are assigned to the old age

  • Dynamic object age judgment: If the total size of all objects of the same age in the Survivor zone is greater than half of the size of the survivor zone, objects older than or equal to this age can enter the old age directly without waiting until the age specified in MaxTenuringThreshold.

  • Space allocation to guarantee: – Xx: HandlePromotionFailure

Garbage collection GC

JVM GC does not always collect all three memory regions at once, but most of the time it collects the new generation. In the implementation of Hotspot VM, there are two types of GC according to the collection region: Partial GC and FullGC.

  • Partial collection: Garbage collection that does not collect the entire Java heap. Which are divided into:

(1) MinorGC/YoungGC: Just garbage collection for the new generation

(2) Old age collection (MajorGC/OldGC) : just old age garbage collection. Currently, only CMSGC has the behavior of collecting old age separately. In many cases, the Major GC will be confused with the FullGC.

(3) MixedGC: Collect garbage collection of the whole new generation and part of the old generation. Currently, only the G1 GC has this behavior

  • FullGC: Collects garbage collection for the entire Java heap and method area.

Minor GC trigger mechanism:

  • MinorGC is triggered when the young generation runs out of space, and when the young generation is full it means Eden is full, and when Survivor is full it does not trigger GC. (Each Minor GC cleans up the memory of the young generation.)

  • Because Java objects are mostly ephemeral, Minor GC is frequent and generally fast. This definition is clear and easy to understand.

  • The Minor GC raises STW (Stop the Word), which pauses other users’ threads until the garbage collection is complete

Major GC trigger mechanism:

  • Refers to a GC that occurs in the old age. When an object disappears from the old age, we say that a “Major GC” or “Full GC” occurs

  • MajorGC occurs, often accompanied by at least one MinorGC (but not always, as is the case with the Paralle1 Scavenge avenge strategy), which attempts to trigger a MinorGC first when the old age is out of space. If there is not enough space after that, the Major GC is triggered

  • Major GC is typically 10 times slower than MinorGC and STW is longer.

  • If the memory is insufficient after Major GC, an OOM exception is reported. (When the OOM is triggered, it must be a Full GC, because the OOM exception will only be emitted when there is not enough space in the old era)

Full GC trigger mechanism:

  • When system.gc () is called, Full GC is recommended, but not necessarily executed

  • There is not enough space in the old era

  • Method area space is insufficient

  • The average size entering the old age after passing the Minor GC is greater than the memory available for the old age

  • If the object size is larger than the available memory of survivor Spacee (From Space) To survivor Spacel (To Space), the object is migrated To the old age, and the available memory of the old age is smaller than the object size

Note: Full GC is something to avoid in development or tuning, so that pause times (STW times) are shorter

Generation idea of heap space:

Why is the Java heap generational? Can’t it work without generations? According to research, the life cycle of different objects is different. 70-99% of objects are temporary objects.

  • New generation: Composed of Eden and two survivor (also called FROM /to, S0 / S1) of the same size, to is always empty.

  • Old age: Stores objects that have survived multiple GC cycles in the New generation.

The only reason for generational is to optimize GC performance. If there is no generation, then all the objects are in one place, and the GC needs to find out which objects are useless, so that all areas of the heap are scanned. A lot of objects are dead, so if you put the new object in a certain place, when GC is the first time to collect the “dead” object area, this will free up a lot of space.

Allocate memory TLAB for objects

What is TLAB?

  • TLAB: Thread Local Allocation Buffer. The JVM allocates a private cache area to each Thread, which is contained in the Eden space.

  • When multiple threads allocate memory simultaneously, TLAB can avoid a series of non-thread-safe problems and improve the throughput of memory allocation, so we can call this memory allocation method as fast allocation strategy.

  • All JVMS derived from OpenJDK provide a TLAB design.

Why TLAB?

  • The heap is a thread shared area where any thread can access the shared data

  • Because object instances are created so frequently in the JVM, it is not thread-safe to partition memory from the heap in a concurrent environment

  • In order to avoid multiple threads operating on the same address, it is necessary to use mechanisms such as locking, which will affect the allocation speed.

  • Although not all object instances can successfully allocate memory in TLAB, the JVM does use TLAB as the first choice for memory allocation.

  • In the program, the developer can set whether to enable the TLAB space with the option “-xx :UseTLAB”.

  • By default, TLAB memory space is very small, only accounts for 1% of the whole Eden space and, of course, we can be set through the option “Xx: TLABWasteTargetPercent TLAB space occupied the percentage of Eden space size.

  • When an object fails to allocate memory in TLAB space, the JVM tries to allocate memory directly in Eden space by using locking mechanisms to ensure atomicity of data operations.

Escape analysis

Is the heap the only option for allocating objects?

As JIT compile-time advances and escape analysis techniques mature, on-stack allocation and scalar replacement optimization techniques will lead to subtle changes in how all objects allocated to the heap become less “absolute.”

It is common knowledge in Java virtual machines that objects are allocated memory in the Java heap. However, there is a special case where an object may be optimized for stack allocation if, after Escape Analysis, it is found that there is no Escape method. This eliminates the need to allocate memory on the heap and garbage collection. This is also the most common out-of-heap storage technique.

Escape analysis:

  • How to allocate objects on the heap to the stack requires the use of escape analysis.

  • This is a cross-function global data flow analysis algorithm that can effectively reduce the synchronization load and memory heap allocation stress in Java programs. Through escape analysis, the Java Hotspot compiler can figure out how far a new object’s references are used to determine whether to allocate the object to the heap.

  • The basic behavior of escape analysis is analyzing object dynamic scope:

◉ When an object is defined in a method and is used only inside the method, no escape is considered to have occurred.

◉ An object is considered to have escaped when it is defined in a method and referenced by an external method. For example, as a call parameter to be passed elsewhere.

  • Objects that do not escape can be allocated to the stack. At the end of the method execution, the stack space is removed. Each stack contains many stack frames, which is the escape analysis

Escape analysis examples:

Examples of complete escape analysis code:

A quick way to determine if escape analysis has occurred is to see if the object entity of new is called outside the method.

Parameter Settings:

Escape analysis has been enabled in HotSpot by default since JDK 1.7

If you are using an earlier version, you can use:

  • The option “-xx: +DoEscapeAnalysis” explicitly turns on escape analysis

  • View the filter results of escape analysis with the option “-xx: +PrintEscapeAnalysis”

  • conclusion

Summary: If you can use local variables in your development, do not define them outside the method.

Using escape analysis, the compiler can optimize code as follows:

Stack allocation:

  • Convert heap allocation to stack allocation. If an object is allocated in a subroutine so that Pointers to the object never escape, the object may be a candidate for stack allocation, not heap allocation.

  • The JIT compiler, based on the results of escape analysis at compile time, finds that an object can be optimized for stack allocation if it does not escape the method. After allocation, execution continues in the call stack, and finally the thread terminates, the stack space is reclaimed, and the local variable object is reclaimed. This eliminates the need for garbage collection.

Synchronous ellipsis:

  • If an object is found to be accessed by only one thread, operations on the object can be performed without regard to synchronization.

  • The cost of thread synchronization is quite high, and the consequence of synchronization is reduced concurrency and performance.

  • When a synchronized block is dynamically compiled, the JIT compiler can use escape analysis to determine whether the lock object used by the synchronized block can only be accessed by one thread and not published to other threads. If not, the JIT compiler unsynchronizes the code when it compiles the synchronized block. This can greatly improve concurrency and performance. This unsynchronization process is called synchronization elision, also known as lock elimination.

Separated objects or scalar substitutions:

  • Some objects may be accessible without needing to exist as a continuous memory structure, and some (or all) of the object may be stored not in memory, but in CPU registers.

  • In THE JIT stage, if an object is found not to be accessed by the outside world after escape analysis, then the OBJECT will be disassembled into several member variables contained in it to be replaced by JIT optimization. This process is called scalar substitution.

  • Scalar: A quantity which cannot be decomposed into any smaller quantities. Primitive data types in Java are scalars.

  • Aggregates: In contrast, data that can be decomposed. Objects in Java are aggregates because they can be decomposed into other aggregates and scalars.

Today’s share has ended, please forgive and give advice!