The JDK version for the following tests is 1.8, and the garbage collector is PS + Po

The main feature of Java is that it takes the developer’s attention off memory allocation and collection. In previous articles, we explained how to determine garbage objects and garbage collection algorithms, as well as the garbage collector. Let’s talk about object memory allocation.

As mentioned above, objects are allocated on the heap. Objects are mainly allocated on Eden, but they may also be allocated on TLAB according to thread priority. In rare cases, they may be directly allocated in the old age. Where allocations are made is not 100 percent fixed, and is influenced by the combination of garbage collectors and memory-related parameter Settings in the virtual machine.

The JVM itself will consume some memory. There are no objects, but Eden will consume nearly 3M:

Configuration is as follows

To view the VM garbage collection information, run the -xx :PrintGCDetails parameter. The configuration in IDEA is as follows

-xms50m -XMx50m -xmn20m-xx :+PrintGCDetails -xx :+PrintHeapAtGC to control the heap size of this code.

-Xms50m: indicates the minimum heap memory of 50M

-Xmx50m: indicates the maximum heap memory of 50M

-Xmn20m: 20M in the new generation, 30M in the old age

-xx :+PrintGCDetails: Prints GC information

It means that the maximum and minimum size of Java heap are both 50MB and unchangeable. Since the new generation can be divided into Eden zone and two Survivor zones (from zone and to zone) with a ratio of 8:1:1, Eden zone is about 16M, from zone and to zone are 2M each. Refer to heap memory generation.

1. Objects are allocated in Eden area first

In most cases, objects are allocated to the Eden region of the new generation (most objects die overnight), and the virtual machine initiates a Minor GC when the memory in Eden region runs out.

The following code

/** * VM parameters: -xms50m -xmx50m -xmn20m-xx :+PrintGCDetails */
public class Allocation {
    private static final int _1MB = 1024 * 1024;
​
    private static void testAllocation(a){
        byte[] one = new byte[5*_1MB];
        byte[] two = new byte[5*_1MB];
    }
​
    public static void main(String[] args) { testAllocation(); }}Copy the code

Run to see if this size and scale is split, and the GC log is shown below

Eden Space 15360K,from space 2560K, and to space 2560K are Eden =16MB, FROM =2MB, to=2MB, respectively. The total available space of the new generation is 17920K(Eden area +1 Survivor area). Pretty much the same as before

The Eden space in the log is 15360K, 87%, indicating that 87% of the Eden space is occupied, about 13MB. There are only two objects in the code, each 5MB. Why 13MB

According to the logs, one and two objects are directly allocated to the Eden area.

2. Big objects go straight to the old age

A large object is a Java object that requires a large amount of contiguous memory. The most typical large object is a very long string or an array with a large number of elements. The byte[] array in this example is a typical large object. If an object is very large, even if there is space in the memory during memory allocation, garbage collection cannot be allocated to the object due to the discontinuous space, and at the same time, the replication of the large object between Eden and two Survivor zones can be avoided (try to avoid the appearance of the large object during development).

-xx: PretenureSizeThreshold is only valid for Serial and ParNew censors. Other censors of HotSpot such as the Parallel Insane do not support this parameter. If you must use this parameter for tuning, consider a collector combination of ParNew plus CMS. —– from Understanding virtual Machines in Depth

1.8 The default garbage collector is PS + Po, so this parameter has no effect and we test directly with larger objects here.

The configuration is the same as before, and the Eden size is 16M.

/** * VM parameters: -xms50m -xmx50m -xmn20m-xx :+PrintGCDetails */
public class Allocation {
    private static final int _1MB = 1024 * 1024;
​
    private static void testAllocation(a){
        byte[] one = new byte[20*_1MB];
    }
​
    public static void main(String[] args) { testAllocation(); }}Copy the code

The GC log is as follows

For example, ParOldGen total 30720K and used 20480K indicate that about 20MB is used in the old age. Because the object is large this time and Eden does not have enough memory, the object is directly allocated to the old age.

3. Long-lived objects will enter the old age

Every object in the virtual machine has an age. An object is usually born in Eden, and if it survives after the first Minor GC and can be accommodated by Survivor, it is moved to Survivor and its object age is set to 1. Each time an object survives a Minor GC in a Survivor zone, its age increases by one year, and when it reaches a certain age (15 by default), it is promoted to the old age. The age threshold for the object to be promoted to the old age can be set by using -xx :MaxTenuringThreshold.

Change of VM: age set 1, new generation size 10M

-Xms50m -Xmx50m -Xmn10m -XX:+PrintGCDetails -XX:MaxTenuringThreshold=1

/** * VM parameters: -xms50m -XMx50m -xmn10m -xx :+PrintGCDetails -xx :MaxTenuringThreshold=1 */
public class Allocation {
    private static final int _1MB = 1024 * 1024;
    private static void testAllocation(a){
        byte[] one = new byte[_1MB / 4];  // Smaller objects can be saved to Survivor
        byte[] two = new byte[2 * _1MB];  
        byte[] three = new byte[2 * _1MB];
        byte[] four = new byte[2 * _1MB];  // This is where the first GC occurs
        System.out.println("= = = = = = =");
        byte[] five = new byte[2 * _1MB];
        byte[] six = new byte[2 * _1MB];
        System.out.println("= = = = = = =");
        byte[] seven = new byte[2 * _1MB];  // A second GC occurs here
    }
​
    public static void main(String[] args) { testAllocation(); }}Copy the code

The normal process is that one,two and three are in Eden area. When four objects are allocated, Eden space is insufficient to trigger GC. One object is relatively small and will enter Survivor area,two and three will move to the old age, and then four objects will enter Eden area. Then five, six, and Seven objects are allocated to Eden. When seven objects are allocated, Eden space is insufficient to trigger GC again. Since the age of one object reaches 1, it will enter the old age.

It can be seen from the above log that 992k is left in the new generation after the first GC (including), 192k is left in the second GC is less than the size of one object (as for why it is not clean, I am not clear about this, if you know, please tell me).

I put -xx :MaxTenuringThreshold=15 to see the log

As shown in the figure, 912K remained in the young generation after the second GC, little changed from 992K in the first GC, indicating that the ONE object was still under age and still survived in the Survivor zone.

4. Dynamic object age determination

The vm is determined by the age of dynamic objects rather than by the object age threshold -xx :MaxTenuringThreshold.

The so-called dynamic object age judgment is to calculate the size of all the objects in the Survivor zone from the object with age 1 to the object with age N. If the age of the object is more than half of the Survivor zone when the age n is accumulated, all the objects with age greater than or equal to n will be moved to the old age. It is not an accumulation of objects of a particular age (the description in the book is misleading)

The rule is such a rule, but I did not test the code successfully by following this rule, and there are still many Survivor zones at the end

5. Space allocation guarantee

Before a Minor GC occurs, the virtual machine must first check that the maximum contiguous space available for the old generation is greater than the total space available for all objects of the new generation. If this condition is true, then the Minor GC is safe for this time. If not, then the virtual opportunity to check the – XX: HandlePromotionFailure parameter setting values are allowed to guarantee Failure (Handle Promotion Failure); If allowed, it continues to check whether the maximum available contiguous space of the old age is greater than the average size of the objects promoted to the old age, and if so, a Minor GC is attempted, although this Minor GC is risky; If less than, or – XX: HandlePromotionFailure Settings do not allow the risk, it would then to conduct a Full GC. —– excerpted from Understanding virtual Machines

Above is a guarantee of space distribution rule, but has expired, the JDK 6 Update after 24 – XX: HandlePromotionFailure parameters won’t affect the spatial distribution of the virtual machine guarantee strategy. The rule changes to Minor GC as long as the continuous space of the old generation is larger than the total size of the new generation object or the average size of the previous promotions, otherwise Full GC will be performed. The following

6. Object stack allocation

In addition to the most basic allocation principles in the above 5, the stack allocation is also designed. In order to reduce the number of objects allocated in the heap, the JVM uses escape analysis to determine whether objects will be referenced externally. Objects that do not escape can be allocated directly on the stack (without gc intervention, objects on the stack will reclaim memory along with methods), reducing the pressure on the GC.

There is also a TLAB Allocation Buffer, which is called Thread Local Allocation Buffer. The TLAB occupies the Eden space. If the TLAB is enabled, the VIRTUAL machine allocates one TLAB space to each Java Thread. The JVM uses TLAB to avoid multithreaded conflicts, and when allocating memory to objects, each thread uses its own TLAB, which avoids thread synchronization and improves the efficiency of object allocation.

conclusion

This paper introduces the design of classical generational five basic principles of memory allocation: object priority in Eden area distribution, large object directly into old age, long-lived objects into old age, dynamic object age determination guarantee and spatial distribution, there are also exist on the stack (escape analysis) and thread local buffer (TLAB)

Stack allocation ->TLAB-> New Generation -> Old generation

The original address


I am Mr. Ji, with the output force input and continue to learn, continue to share the series of technical articles, as well as the whole network worth collecting good articles, welcome to pay attention to the public number, do a continuous growth of technical people.

Personal website

The JVM virtual machine series historical articles

1. Virtual Machine series: how to divide JVM runtime heap memory;

2. Virtual Machine series: Garbage collection algorithm in JVM;

3. Virtual Machine Series: JVM runtime data area;

4. Virtual Machine series: creation of objects in JVM, memory layout and access location;

5. Virtual Machine Family: Garbage collector in JVM