The heap is created and sized at startup and is the largest and most important chunk of memory in the JVM. The heap is physically discontinuous, but logically continuous. Although the heap is shared per thread, it can also be partitioned into thread-private buffers.

Almost all object instances and arrays are allocated in the heap, with a small proportion allocated in the stack. Objects and arrays may never be stored on the stack, and only references are held in the stack frame, which point to locations in the heap. Objects in the heap are not removed immediately after the stack frame ends, but only during garbage collection.

The method area and heap space of the VIRTUAL machine are shared by each thread, while other data areas are private to each thread. The granularity of the private data area is relatively fine, so it is difficult to optimize the space. The common data area, however, can get more memory when allocating memory, so it is the focus of GC.

New generation and old age

Before Java7, the heap space was logically divided into: new generation + old generation + permanent generation; In Java8 and later, it is divided into: freshmen + seniors + meta-space

Permanent generation and meta-space are concrete implementations of method areas, also known as non-heap, so permanent generation and meta-space are not actually belonging to the heap, just logical partition.

Java objects stored in the JVM can be divided into two categories: transient objects with short surface cycles that are created and die very quickly; Another class of objects has a very long lifetime and, in extreme cases, can persist with the JVM’s lifetime, such as the Runtime class

Why do you need memory partitioning? A large number of data show that different objects have different life cycles, 70%~90% of objects are temporary objects, and generational objects can be more purposeful for GC and optimize GC performance.

The new generation

The new generation can be divided into Eden, Survivor0 and Survivor1, and Survivor0 and Survivor1 are sometimes called from and to.

  • Eden: The location where objects (almost all) are originally created.
  • Survivor0 and Survivor1: Survivor0 and Survivor1: Eden objects that have not been cleared by GC are placed in S0 and S1, where S0 and S1 have the same size and only one space for objects and one space for full GC.

The vast majority of Java objects are destroyed in the new generation, and IBM research shows that 80% of objects in the new generation die.

The old s

Heap space in addition to the new generation is the old age.

The process of allocating objects in the heap

1. Objects are allocated to Eden zone at first. When Eden zone is full, Young GC will be performed and the surviving objects will be moved to Survivor zone. Each object has an age counter that is 0 in Eden and 1 when moved to S. Full S-block does not trigger YGC.

2. The age counter continues to +1 for objects that survive the second GC in S. When the age counter reaches 15, the corresponding object will be moved (promotion) to the old area. You can set this value by running -xx :MaxTenuringThreshold=15.

3. If the space occupied by the object is too large and YGC continues to exceed the space in Eden area, the object will be directly allocated to the old age. If not, perform Full GC. If not, perform OOM. After YGC, objects living in Eden zone will be directly allocated to the old age if they cannot be placed in S zone.

Parameters related to heap memory Settings

  • -XmsRepresents the starting memory of the heap (new generation and old age)

All called – XX: InitialHeapSize

X is the running parameter of the JVM, and MS is memory start. The default unit is k, M, and G bytes

  • -XmxRepresents the maximum memory of the heap

All called – XX: MaxHeapSize

Default heap size:

-xms = Computer memory size /64

-xmx = Computer memory size /4

Once the maximum memory specified by -xmx is exceeded, an OutOfMemoryError is thrown. The two parameters are usually set to the same value to improve performance without the need to reseparate the heap size calculations once the garbage is collected.

You can check the heap size of the JVM by using:

// -xms heap start value, s0,s1 only count one of them
long initalMemory = Runtime.getRuntime().totalMemory() / 1024 / 1024
// -maximum Xmx heap size
long maxMemory = Runtime.getRuntime().maxMemory() / 1024 / 1024
Copy the code

Disable the adaptive memory allocation policy

-xx: -useadaptivesizePolicy :- Indicates that adaptivesizePolicy is disabled. + indicates that adaptivesizePolicy is enabled

Configuration of Cenozoic and old age in the proportion of the structure

  • Default -xx :NewRatio=2, indicating that the Cenozoic era accounts for 1, the old age accounts for 2, and the Cenozoic era accounts for 1/3 of the whole heap. It can be modified to -xx :NewRatio=4, indicating that the Cenozoic era accounts for 1, the old age for 4, and the Cenozoic era accounts for 1/5 of the whole heap

  • In HotSpot, the default ratio of Eden to S0 and S1 is 8:1:1, which can be adjusted by -xx :SurvivorRatio=8

Configures the maximum memory size for the new generation

  • -XmnGenerally, the default value is ok. If there is any setting, use this parameter.

Heap-specific GC

Instead of collecting garbage as a whole, the JVM collects frequent new generations, less old ones, and almost no permanent generation/meta-space collections.

  • Minor GC, which only collects garbage for the new generation. It is triggered when the Eden region is out of memory and does not collect garbage when the Survivor region is full.

  • Major GC, which only does garbage collection for older generations

    Currently only the CMS GC will have a separate collection behavior for older generations

    Most of the time, the Major GC will be confused with the Full GC, and you need to be specific about whether it is old age or whole heap

    A Major GC is often accompanied by a Minor GC, in which an attempt is made to trigger a Minor GC when there is not enough space in the old decade, and then a Major GC is triggered when there is not enough space. Major GC is more than ten times slower than Minor GC and has a longer STW.

    Try to avoid

  • Mixed GC, which collects garbage from the new generation and part of the old generation, only appears in G1 GC

  • Full GC, which collects garbage from the entire Java heap and method area

    When system.gc () is called, Full GC is recommended, but not necessarily executed; Lack of space in the old era; Insufficient method area space; The average size of the old age after the Minor GC is greater than the available memory of the old age; Old age can not put the big objects from Eden district;

    Try to avoid

Heap memory allocation policy

  • Priority allocated to Eden district
  • Large objects are allocated directly to the old age to avoid excessive large objects in the program
  • Long-lived objects are assigned to the old age
  • Dynamic object age judgment,If the sum of the size of all objects of the same age in the Survivor zone is greater than half of the space in the S-zone, the objects of greater than or equal age can enter the old age directly without waiting for the age required by MaxTenuringThreshold
  • Space allocation, – XX: HandlePromotionFailure

Thread private space for heap memory: TLAB

TLAB: ThreadLocal Allocation Buffer

A heap is an area shared by threads that can be accessed by any thread. 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. To avoid multiple threads operating on the same address, mechanisms such as locking are needed, which affects allocation speed. Therefore, it is necessary to allocate a separate area for each thread to store data, which exists in Eden area. This strategy is also called fast allocation strategy.

Although not all object instances can successfully allocate memory in TLAB, the JVM does use TLAB as the first choice for memory allocation. You can set whether to enable UseTLAB by -xx :UseTLAB. By default, TLAB space is very small, only about 1% of Eden area, can pass – XX: TLABWasteTargetPercent set the percentage occupied.

In the event that an object fails to be allocated in TLAB, the JVM tries to lock to ensure atomicity of the data operation so that it is allocated directly in Eden.