This article has participated in the third “topic writing” track at the Diggings Creators Camp. For more details, check out diggings program | Creators Camp.

For Java applications, the Java Heap is the largest chunk of memory managed by the virtual machine. The Java heap is an area of memory shared by all threads and created when the virtual machine starts. The only purpose of this memory area is to hold object instances, and all object instances are allocated memory here.

The Java heap is an area of memory managed by the garbage collector. From the point of view of recycling memory, since most garbage collectors are designed mostly on the basis of generational collection theory, there are often “new Generation”, “old generation”, “permanent generation”, “Eden space”, “From Survivor space”, “To Survivor space” and so on in the Java heap. These partitions are a common feature or design style of a subset of garbage collectors, not an inherent memory layout of a specific Java virtual machine implementation, or the official definition of a Java heap in the Java Virtual Machine Specification. For example, Shenandoah and ZGC do not support generations.

JDK 1.7 generational structure

In JDK 1.7 and before, the heap space was divided into three parts: new generation, old generation, and permanent generation. Then the Cenozoic is divided into Eden zone and two Survivor zones. As shown in the figure below:

,

JDK 1.8 generational structure

In JDK 1.8 and later, permanent generations were removed from the heap space. Why remove the cause of the permanent generation can read the following document: openjdk.java.net/jeps/122. The core reasons are as follows:

  1. This is Hotspot and JRockit virtual machine fusion. JRockit customers do not need to configure permanent generations (because JRockit does not have permanent generations) and it is customary not to configure permanent generations.
  2. Increases the amount of memory required for the meta-space to handle class loading, and the meta-space is automatically extensible by default. This reduces the possibility of memory overruns.

After the permanent generation of the heap space is removed, the heap space structure is as follows:

The runtime data area structure is shown in the figure below:

G1 collector

G1 cancels the division of physical space between the old and the new. Instead, the G1 algorithm divides the heap into regions, which are still part of the generational collector. However, some of these areas contain the new generation, which still suspends all application threads and copies the surviving objects to the old or Survivor space. The old age is also divided into regions, and the G1 collector cleans up by copying objects from one region to another. This means that during normal processing, G1 compresses the heap (at least partially) so that there is no problem with CMS fragmentation.

There’s also a special region in G1 called the Humongous region. The G1 collector considers an object to be a giant if it occupies more than 50% of the partition’s capacity. These giant objects, by default, are directly allocated in the tenderly generation, but if it is a short-lived giant object, it can have a negative impact on the garbage collector. To solve this problem, G1 divides a Humongous region, which is dedicated to giant objects. If a single h-block doesn’t fit a giant object, G1 will look for contiguous H-partitions to store it. In order to find continuous H blocks, you sometimes have to start Full GC.

Object memory allocation

The object memory allocation process is as follows:

Here are some specific memory allocation rules

Objects are first allocated in Eden

In most cases, objects are allocated in the Cenozoic Eden zone. If the Eden zone does not have enough space, the VM initiates a Minor GC. The HotSpot virtual machine provides the collector log parameter -xx :+PrintGCDetails, which tells the virtual machine to print the memory reclamation log when garbage collection occurs, and to print the current memory region allocation when the process exits.

Test code:

/** * -XX:+PrintGCDetails */
public class GCTest {

    public static void main(String[] args) {
        byte[] allcation2 = new byte[8000 * 1024]; }}Copy the code

The output

Heap PSYoungGen total 38400K, used 11353K [0x0000000795580000, 0x0000000798000000, 0x00000007c0000000) eden space 33280K, 34%, informs [x0000000795580000 0, 0 x00000007960966f8, 0 x0000000797600000) from space 5120 k, 0%, informs [x0000000798000000 x0000000797b00000 0, 0 x0000000797b00000, 0) to space 5120 k, 0%, informs [x0000000797600000 0, 0 x0000000797600000, 0 x0000000797b00000) ParOldGen total 87552 k, 2 0 k [0 x0000000740000000, 0x0000000745580000, 0x0000000795580000) object space 87552K, 0%, informs [x0000000740000000 0, 0 x0000000740000000, 0 x0000000745580000) Metaspace informs the 3017 k, capacity 4556 k, committed 4864K, reserved 1056768K class space used 319K, capacity 392K, committed 512K, reserved 1048576KCopy the code

We can see from the memory space distribution that Allcation2 is allocated to the Eden zone.

Big objects go straight into the old age

A large object is a Java object that requires a large amount of contiguous memory space (for example: Strings, arrays), the JVM parameter – XX: PretenureSizeThreshold parameter can be set the size of large object, the specified is greater than the set value of objects directly in the old s distribution, not the young generation, this parameter is only effective under two Serial and ParNew collector.

For example, set: JVM parameters:

– XX: PretenureSizeThreshold = 1000000 (in bytes)

-XX:+UseSerialGC

In executing the first program above, you will see that large objects go straight into the old age. The purpose of this is to avoid copying back and forth between the Eden and two Survivor extones, resulting in a large number of memory replicates.

Long-lived objects will enter the old age

Most collectors in a HotSpot virtual machine use generational collection to manage the heap memory, so memory reclamation must be able to decide which surviving objects should be placed in the new generation and which surviving objects should be placed in the old generation. To do this, the virtual machine defines an object Age counter for each object, which is stored in the object header.

Objects are usually born in Eden, and if they survive the first Minor GC and can be held by a Survivor, they are moved to the Survivor space and their object age is set to 1 year. The age of the object increases by one year for every Minor GC it survives in the Survivor zone, and when it increases its age to a certain level (the default is 15), it is promoted to the old age. The age threshold for an object to be promoted to an old age can be set by -xx :MaxTenuringThreshold.

Dynamic object age judgment

In order to better adapt to the memory conditions of different applications, the HotSpot virtual machine does not always require objects to reach -xx :MaxTenuringThreshold in order to be promoted. If the sum of the sizes of all objects of the same age in the Survivor space is greater than half of the size of the Survivor space, objects whose age is greater than or equal to that age can go straight to the old age without waiting for the age required in -xx :MaxTenuringThreshold.

Space allocation guarantee

Before a Minor GC can occur, the virtual machine must first check whether the maximum continuous space available in the old generation is greater than the total space of all objects in the new generation.

The reference information

  • Deeper understanding of the JVM Virtual Machine – 3rd edition. By Zhiming Zhou
  • www.infoq.cn/…
  • www.cnblogs.com/..