Home  >  Article  >  Java  >  Java memory allocation and recycling strategy analysis

Java memory allocation and recycling strategy analysis

怪我咯
怪我咯Original
2017-07-02 10:35:351316browse

The following editor will bring you an in-depth understanding of Java memory allocation and recycling strategies. The editor thinks it’s pretty good, so I’ll share it with you now and give it as a reference. Let’s follow the editor and take a look.

1. Introduction

The automatic memory management mentioned in the Java technical system is ultimately about memory. Regarding the two issues of allocation and recycling, I have talked to you about Java recycling before. Today I will talk to you about the allocation of Java objects in memory. In layman's terms, the memory allocation of objects is the allocation on the heap. The objects are mainly allocated on Eden of the new generation (the generation of objects in memory will be supplemented during garbage collection. If you want to know more, you can also refer to "In-depth Understanding" Java Virtual Machine"), if the local thread allocation buffer is started, it will be allocated on the TLAB according to thread priority. In a few cases, it is also allocated directly in the old generation.

2. Classic allocation strategy

1. Objects are allocated first on Eden

Under normal circumstances, objects are allocated on Eden first. When Eden does not have enough space for allocation, jvm will initiate a Minor GC. If there is still not enough space allocated, there are other measures later, which will be mentioned below.

Set the virtual machine's even log parameter -XX:+PrintGCDetails. During garbage collection, the memory recycling log will be printed, and when the process exits , the current memory areas will be output. distribution situation. Let's look at a specific example. First, you need to set the jvm parameters -Xms20m -Xmx20m -Xmn10m. These three parameters indicate that the Java heap size is 20M and cannot be expanded. 10M is allocated to the new generation and the remaining 10M is allocated to the old generation. Era. -XX:SurvivorRatio=8 is the default ratio of Eden and Survivor in the new generation of jvm. The default is 8:1. The reason is that 98% of the objects in the new generation will be recycled during the next GC, so it is very suitable to use the copy algorithm for garbage collection. Therefore, of the 10M memory in the new generation, 8M is Eden, 1M is Survivor, and the other 1M is unused. The memory block that cooperates with the copy algorithm is also a Survivor.

public class ReflectTest {

  private static final int _1MB = 1024*1024;
  
  public static void testAllocation(){
    byte[] allocation1 , allocation2 , allocation3 , allocation4;
    allocation1 = new byte[2 * _1MB];
    allocation2 = new byte[2 * _1MB];
    allocation3 = new byte[2 * _1MB];
    allocation4 = new byte[6 * _1MB];
  }
  
  public static void main(String[] args) {
    ReflectTest.testAllocation();
  }
  
}

The output is as follows

Heap
 PSYoungGen   total 9216K, used 6651K [0x000000000b520000, 0x000000000bf20000, 0x000000000bf20000)
 eden space 8192K, 81% used [0x000000000b520000,0x000000000bb9ef28,0x000000000bd20000)
 from space 1024K, 0% used [0x000000000be20000,0x000000000be20000,0x000000000bf20000)
 to  space 1024K, 0% used [0x000000000bd20000,0x000000000bd20000,0x000000000be20000)
 PSOldGen    total 10240K, used 6144K [0x000000000ab20000, 0x000000000b520000, 0x000000000b520000)
 object space 10240K, 60% used [0x000000000ab20000,0x000000000b120018,0x000000000b520000)
 PSPermGen    total 21248K, used 2973K [0x0000000005720000, 0x0000000006be0000, 0x000000000ab20000)
 object space 21248K, 13% used [0x0000000005720000,0x0000000005a07498,0x0000000006be0000)

You can see that eden occupies 81%, indicating that allocation1, allocation2, and allocation3 are all allocated on the new generation Eden.

2. Large objects are directly allocated in the old generation.

Large objects refer to objects that require a large amount of continuous memory space to store, similar to The kind of very long strings and arrays. Large objects are not a good thing for the memory distribution of the virtual machine. It is more difficult for the JVM to handle many large objects that only survive for one round. Such problems should be avoided when writing code. The -XX:PretenureSizeThreshold parameter is provided in the virtual machine. Objects larger than this value are directly allocated to the old generation. The purpose of this is to avoid a large amount of memory copy between the Eden area and the Survivor area. The garbage mentioned before The recycling algorithm and copying algorithm have been mentioned before, so I won’t go into details.

public class ReflectTestBig {

  private static final int _1MB = 1024*1024;
  
  public static void testAllocation(){
    byte[] allocation2 , allocation3 , allocation4;
    allocation2 = new byte[2 * _1MB];
    allocation3 = new byte[2 * _1MB];
    allocation4 = new byte[6 * _1MB];
  }
  
  public static void main(String[] args) {
    ReflectTestBig.testAllocation();
  }
  
}

The output is as follows

Heap
 PSYoungGen   total 8960K, used 4597K [0x000000000b510000, 0x000000000bf10000, 0x000000000bf10000)
 eden space 7680K, 59% used [0x000000000b510000,0x000000000b98d458,0x000000000bc90000)
 from space 1280K, 0% used [0x000000000bdd0000,0x000000000bdd0000,0x000000000bf10000)
 to  space 1280K, 0% used [0x000000000bc90000,0x000000000bc90000,0x000000000bdd0000)
 PSOldGen    total 10240K, used 6144K [0x000000000ab10000, 0x000000000b510000, 0x000000000b510000)
 object space 10240K, 60% used [0x000000000ab10000,0x000000000b110018,0x000000000b510000)
 PSPermGen    total 21248K, used 2973K [0x0000000005710000, 0x0000000006bd0000, 0x000000000ab10000)
 object space 21248K, 13% used [0x0000000005710000,0x00000000059f7460,0x0000000006bd0000)

You can see that allocation4 has exceeded the set -XX:PretenureSizeThreshold=3145728. Allocation4 is directly allocated to the old generation, and the old generation occupancy rate is 60%. Note that the setting -XX:PretenureSizeThreshold=3145728 cannot be written as -XX:PretenureSizeThreshold=3m, otherwise the jvm will not be recognized.

3. Long-term surviving objects will enter the old generation

Since the virtual machine adopts the idea of ​​strip collection to manage memory, the memory Recycling must identify which objects should be placed in the new generation and which objects should be placed in the old generation. In order to achieve this purpose, jvm defines an age counter (Age) for each object. If the object is born in Eden and survives the first Minor GC, and can be stored in the Survivor, it will be moved to the Survivor and the object's age will be set to 1. Every time an object escapes Minor GC, its age will be increased by 1. When its age exceeds the threshold of one year, the object will be promoted to the old generation. This threshold jvm defaults to 15 and can be set by -XX:MaxTenuringThreshold.

public class JavaTest { 
 
  static int m = 1024 * 1024; 
 
  public static void main(String[] args) { 
    byte[] a1 = new byte[1 * m / 4]; 

     byte[] a2 = new byte[7 * m]; 

     byte[] a3 = new byte[3 * m]; //GC 
  } 
}

The output is as follows

[GC [DefNew: 7767K->403K(9216K), 0.0062209 secs] 7767K->7571K(19456K), 0.0062482 secs]  
[Times: user=0.00 sys=0.00, real=0.01 secs]  
a3 ok 
Heap 
 def new generation  total 9216K, used 3639K [0x331d0000, 0x33bd0000, 0x33bd0000) 
 eden space 8192K, 39% used [0x331d0000, 0x334f9040, 0x339d0000) 
 from space 1024K, 39% used [0x33ad0000, 0x33b34de8, 0x33bd0000) 
 to  space 1024K,  0% used [0x339d0000, 0x339d0000, 0x33ad0000) 
 tenured generation  total 10240K, used 7168K [0x33bd0000, 0x345d0000, 0x345d0000) 
  the space 10240K, 70% used [0x33bd0000, 0x342d0010, 0x342d0200, 0x345d0000) 
 compacting perm gen total 12288K, used 381K [0x345d0000, 0x351d0000, 0x385d0000) 
  the space 12288K,  3% used [0x345d0000, 0x3462f548, 0x3462f600, 0x351d0000) 
  ro space 10240K, 55% used [0x385d0000, 0x38b51140, 0x38b51200, 0x38fd0000) 
  rw space 12288K, 55% used [0x38fd0000, 0x396744c8, 0x39674600, 0x39bd0000)

You can see that a2 has survived once, with an age of 1, which satisfies the set -XX:MaxTenuringThreshold=1, so a2 has entered the old age, while a3 Entered the new generation.

4. Dynamic object age determination

In order to better adapt to the memory status of different programs, the virtual machine does not always require objects The age must reach the value set by -XX:MaxTenuringThreshold in order to be promoted to the old age. If the sum of the sizes of all objects of the same age in the Survivor space is greater than half of the Survivor space, objects whose age is greater than or equal to this age can directly enter the old age. , it is not necessary to reach the setting value in -XX:MaxTenuringThreshold.

5. Space allocation guarantee

When Minor GC occurs, the virtual machine will detect whether the average size of each promotion to the old generation is greater than the remaining space of the old generation. If it is greater, a FUll GC will be performed directly. If it is less than, check whether the HandlerPromotionFailyre setting allows guarantee failure. If it is allowed, only Minor GC will be performed. If it is not allowed, a FUll GC will also be improved. That is to say, when the new generation Eden cannot store the modified object, the object will be stored in the old generation.

3. Commonly used jvm parameter settings

1. -Xms: Initial heap size, default (MinHeapFreeRatio parameter can be adjusted) free heap memory When it is less than 40%, the JVM will increase the heap until the maximum limit of -Xmx.

2.

3. -Xmn: Young generation size (1.4or lator), the size here is (eden+ 2 survivor space). It is different from the New gen shown in jmap -heap.

The entire heap size = young generation size + old generation size + persistent generation size.

After increasing the young generation, the size of the old generation will be reduced. This value has a greater impact on system performance. Sun officially recommends a configuration of 3/8 of the entire heap.

4. -XX:NewSize: Set the young generation size (for 1.3/1.4).

5. -XX:MaxNewSize: The maximum value of the young generation (for 1.3/1.4).

6, -XX:PermSize: Set the initial value of the persistent generation (perm gen).

7, -XX:MaxPermSize: Set the maximum size of the persistent generation.

8. -Xss: The stack size of each thread. After JDK5.0, the stack size of each thread is 1M. In the past, the stack size of each thread was 256K. The memory size required by the application thread can be adjusted. .Under the same physical memory, reducing this value can generate more threads. However, the operating system still has limits on the number of threads in a process and cannot be generated infinitely. The experience value is around 3000~5000.

9, -XX:NewRatio: The ratio of the young generation (including Eden and two Survivor areas) to the old generation (excluding the persistent generation), -XX:NewRatio=4 indicates the difference between the young generation and the old generation The ratio value is 1:4, and the young generation accounts for 1/5 of the entire stack. When Xms=Xmx and Xmn is set, this parameter does not need to be set.

10. -XX:SurvivorRatio: The size ratio of the Eden area and the Survivor area is set to 8, then the ratio of two Survivor areas to one Eden area is 2:8, and one Survivor area accounts for the entire young generation. 1/10.

11. -XX:LargePageSizeInBytes: The size of the memory page cannot be set too large, which will affect the size of Perm.

12. -XX:+DisableExplicitGC: Close System.gc()

13. -XX:MaxTenuringThreshold: The maximum age of garbage. If set to 0, the young generation objects will not pass through Survivor area, directly enter the old generation. For applications with a large number of old generations, efficiency can be improved. If this value is set to a larger value, the young generation objects will be copied multiple times in the Survivor area, so that more objects can be added. The survival time of the young generation increases the probability of being recycled in the young generation. This parameter is only effective in serial GC.

14. -XX:PretenureSizeThreshold: If the object exceeds the size, it is allocated directly in the old generation. The unit byte is invalid when the new generation uses Parallel Scavenge GC. Another situation where it is allocated directly in the old generation is a large array. object, and there are no external reference objects in the array.

15. -XX:TLABWasteTargetPercent: The percentage of TLAB in the eden area.

4. Supplement

The difference between Minor GC and FUll GC:

New generation GC (Minor GC): refers to the garbage collection action that occurs in the new generation. Because most Java objects cannot escape the first round of GC, Minor GC is used frequently. The recycling speed is generally faster.

Old generation GC (FULL GC/Major GC): refers to the GC that occurs in the old generation. When Major GC appears, it is often accompanied by at least one Minor GC (but not absolutely, in The collection strategy of the ParallelScavenge collector includes the direct selection process of Major GC). The speed of Major GC is generally more than 10 times slower than Minor GC.

The above is the detailed content of Java memory allocation and recycling strategy analysis. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn