I. Partition of JVM memory area

1.1 Java VM Running Data Area

Java VIRTUAL Machine running data distinction diagram:

  • Java Virtual Machine Stacks: A thread in Java can have a thread stack accordingly with the matching, because different thread execution logic is different, so we need a separate thread stack, so the stack storage of information are associated with the current thread (or program) information, including local variables, program running state, method return value, export and so on. Each method is called until the execution is complete, corresponding to the process of a stack frame in the virtual machine stack from the stack to the stack.
  • Heap: The Heap is shared by all threads. It holds object instances and arrays. Memory space that is physically discontinuous, as long as it is logically continuous
  • Method Area: a shared memory Area that stores data such as class information loaded by the VM, constants, static variables, and code compiled by the real-time compiler
  • Runtime Constant Pool: This is the part of the method area that holds the various literal and symbolic references generated at compile time.
  • Native Method Stacks: ## 1. Partitioning of JVM memory regions

1.1 Java VM Running Data Area

Java VIRTUAL Machine running data distinction diagram:

  • Java Virtual Machine Stacks: A thread in Java can have a thread stack accordingly with the matching, because different thread execution logic is different, so we need a separate thread stack, so the stack storage of information are associated with the current thread (or program) information, including local variables, program running state, method return value, export and so on. Each method is called until the execution is complete, corresponding to the process of a stack frame in the virtual machine stack from the stack to the stack.
  • Heap: The Heap is shared by all threads. It holds object instances and arrays. Memory space that is physically discontinuous, as long as it is logically continuous
  • Method Area: a shared memory Area that stores data such as class information loaded by the VM, constants, static variables, and code compiled by the real-time compiler
  • Runtime Constant Pool: This is the part of the method area that holds the various literal and symbolic references generated at compile time.
  • Native Method Stacks:

Among them, Heap and JVM stack are the key to run the program because:

  1. The stack is the unit of runtime (solving the problem of how a program executes, or how it handles data), while the heap is the unit of storage (solving the problem of data storage, how and where data is stored).
  2. The heap stores objects. The stack stores references to basic data types and objects in the heap; (Value passing and reference passing for parameter passing)

So why distinguish between heap and stack? Isn’t it possible to store data on a stack?

  1. From the perspective of software design, stack represents processing logic, while heap represents data. The division of labor is clear, and the processing logic more clearly reflects the idea of “divide and conquer” and “isolation”.
  2. The separation of heap and stack allows the contents of the heap to be shared by multiple stacks (also understood as multiple threads accessing the same object). This sharing approach has many benefits: it provides an efficient way to interact with data (e.g., shared memory); Shared constants and caches in the heap can be accessed by all stacks, saving space.
  3. The stack needs to be divided into address segments for runtime purposes, such as storing the context in which the system is running. Since the stack can only grow up, it limits the stack’s ability to store content. Unlike the heap, objects in the heap can grow dynamically as needed, so the separation of stack and heap makes dynamic growth possible, and only one address in the heap is recorded in the corresponding stack.
  4. The combination of heap and stack is perfect for object-oriented design. When we break things apart, you see that the properties of the object are data, stored in the heap; The behavior of the object (method) is to run the logic and put it on the stack. So when you write an object, you’re writing both the data structure and the logic that works with the data.

1.2 Heap and JVM stack:

1.2.1 Heap (Heap)

The Java heap is the largest chunk of memory managed by the Java VIRTUAL machine. It is a physically discontinuous memory space, as long as it is logically continuous. It is mainly used to store instance objects of various classes. This area is shared by all threads, created at virtual machine startup to hold instances of objects, and almost all objects and arrays are allocated memory here (allocation on the stack, with the exception of scalar replacement optimization). In Java, the heap is divided into two distinct regions: Young and Old. The New generation (Young) is divided into three regions: Eden, From Survivor(S0), and To Survivor(S1). As shown in the figure:

Memory layout of the heap:

The purpose of this partition is to enable the JVM to better manage objects in memory, including allocation and reclamation of memory. And the new generation, according to Eden and two survivor classification, is to

  • The effective space increases, Eden +1 survivor;
  • It is beneficial to the calculation of object generation. When an object reaches XX:MaxTenuringThreshold in S0/S1, it will be moved to the old age, that is, only one survivor is scanned. How to calculate how many GCS an object has gone through if there is no S0/S1 and it is split into two partitions.
  • Two Survivor zones resolve memory fragmentation

1.2.2 Stack-related parameters

parameter describe
-Xms Initial size of heap memory, in m or g
-Xmx The maximum allowed size of heap memory should not be greater than 80% of physical memory
-Xmn Initial memory size of young generation
-Xss The stack size per thread, which is the size of the JVM stack
-XX:NewRatio Ratio of young generation (including Eden and two Survivor zones) to old generation
-XX:NewSzie(-Xns) The initial size of young generation memory, can be abbreviated -xns
-XX:MaxNewSize(-Xmx) Maximum allowed memory size for young generation
-XX:SurvivorRatio The ratio of the Eden zone to the Survivor zone in the young generation is 8 by default, that is, 8:1
-XX:MinHeapFreeRatio After GC, if free heap memory is found to be 40% of the total estimated heap memory, the estimated maximum of heap memory is enlarged, but not beyond the fixed maximum.
-XX:MaxHeapFreeRatio Estimating heap memory is one of the important options for dynamic heap size regulation. The estimated maximum heap memory must be less than or equal to the fixed maximum (the value specified by -xmx). The former is dynamically scaled up or down depending on usage to improve the efficiency of GC collection, which defaults to 70%
-XX:MaxTenuringThreshold The maximum age of garbage, if set to 0, the object of the young generation directly enters the old generation without passing through the Survivor zone. For the older generation of more applications, can improve efficiency. If this value is set to a large value, the young generation object will be copied multiple times in the Survivor zone, which increases the lifetime of the object in the young generation and increases the probability that it will be recycled in the young generation
-XX:InitialTenuringThreshold You can set the initial value of the old age threshold
-XX:+PrintTenuringDistribution Check the threshold for new life cycles after each Minor GC

Note: The heap size will be adjusted after each GC. In order to prevent performance loss caused by dynamic adjustment, generally set -xms, -xmx equal. Three new generation parameters: -xmn, -xx :NewSize, -xx :NewRatio Priority: (1) Highest priority: -xx :NewSize=1024m and -xx :MaxNewSize= 1024M (2). Second highest priority: -xmn1024m (default equivalent effect: -xx :NewSize== -xx :MaxNewSize==1024m) (3). Lowest priority: -xx :NewRatio=2 It is recommended to use the -xmn parameter because it is concise and equivalent to setting NewSize and MaxNewSIze at once, and both are equal.

1.3 the JVM object

1.3.1 Method of Creating objects

The essential operation of each mode is as follows:

way The essence
Using new Keys Creates by calling the no-parameter or parameter-constructor function
Use the Class newInstance method Creates a publi constructor by calling the no-argument or argument constructor function
Use the Constructor class’s newInstance method Call parameter and private private constructor function creation, more practical
Using the Clone method No parameter constructor functions are called, and the object needs to implement the Cloneable interface and implement its clone method, which is shallow copy by default
Third-party library Objenesis Using ASM bytecode technology, Constructor objects are generated dynamically

1.3.2 JVM Object Allocation

To create an object at the VM level:

steps parsing
1. Determine whether the corresponding class of the object is loaded, linked, and initialized The virtual machine checks a new instruction to see if its arguments can locate a symbolic reference to a class in the constant pool, and to see if the class represented by the symbolic reference has been loaded, parsed, and initialized. If not, the class must be loaded, interpreted, and initialized (the clinit method of the class) first.
2. Allocate memory for objects After the class load check passes, the virtual machine allocates memory for the new objects. The size of memory required for an object is fully determined after the class is loaded, and allocating space for an object is nothing more than dividing up a certain size of memory from the Java heap.
3. Deal with concurrency security issues Another issue is keeping new objects thread-safe in a timely manner: object creation is a very frequent operation, and the virtual machine needs to deal with concurrency issues. VMS solve concurrency problems in two ways:

(1) CAS is configured with retry mode to ensure atomicity of pointer update operation;

In other words, each Thread allocates a small block of memory in the Java heap in advance, which is called the Thread Local Allocation Buffer. (TLAB, Thread Local Allocation Buffer) This can be set with the -xx :+/ -usetlab parameter.
4. Initialize the allocated space When memory allocation is complete, the virtual machine initializes all allocated memory space to zero (excluding object headers). This step ensures that the instance fields of the object can be used directly in Java code without assigning initial values, and that the program can access the zero values corresponding to the data types of these fields
Set the object header of the object Store data such as the object’s owning class (that is, metadata information about the class), the object’s HashCode, and the object’s GC generation age in the object’s object header
6. Run init to initialize the system From a Java program’s point of view, initialization begins, with methods called to complete the initial assignment and constructor, all fields having zero values. Therefore, in general (depending on whether the bytecode is followed by the Invokespecial instruction), the new instruction will be followed by the implementation method to initialize the object as the programmer wishes, so that a truly usable object is fully created.

1.3.3 How objects allocate Memory

(1) If The memory is regular, The VIRTUAL machine will use a method called Bump The Pointer to allocate memory for objects. This means that all used memory is on one side and free memory is on the other, with a pointer in the middle as a pointer to the dividing point. Allocating memory simply moves the pointer to the free side by a distance equal to the size of the object. If the garbage collector chooses Serial, ParNew, etc. based on compression algorithms, the virtual machine uses this allocation method. Pointer collisions are typically used with collectors with compact processes. (2) If memory is not tidy and used memory is interleaved with unused memory, the virtual machine will use the free list method to allocate memory for objects. The virtual machine maintains a list of memory blocks that are available, finds a large enough chunk of the list to allocate to object instances, and updates the list. This allocation method is called the Free List.

Note: The allocation method chosen depends on whether the Java heap is clean, which in turn depends on whether the garbage collector used has collation capabilities.

1.3.4 What kind of object can enter the Old age

So what kind of objects can go into Old?

1.4 Memory Allocation and Reclaiming Policies

situation parsing
1. Objects are allocated in Eden preferentially In most cases, objects are allocated in the Eden area of the new generation. When the Eden area does not have enough space for allocation, the VIRTUAL machine will initiate a Minor GC. The VM provides the -xx :PrintGCDetails parameter. The memory reclamation log is printed when garbage collection occurs and the current memory allocation information is displayed when the process exits.
2. Big objects go straight to the old age Large objects are Java objects that require a large amount of contiguous memory. The most typical large objects are long strings and arrays. Virtual machine provides a – XX: PretenureSizeThreshold parameters, deserves greater than the set object directly in the old age distribution (the aim is to avoid in the Eden area and a lot of memory copy) between the two Survivor
3. Long-lived objects will go straight into the old age Object age counter. -XX:MaxTenuringThreshold
4, dynamic object age determination The virtual machine does not always require that the object’s age must reach MaxTenuringThreshold to be promoted to the old age. If the sum of all objects of the same age in the Survivor space is greater than half of the size in the Survivor space, the object whose age is greater than or equal to this age can enter the old age directly. There is no need to wait until the age required in MaxTenuringThreshold.
5. Guarantee of space allocation When a Minor GC occurs (before), the virtual machine checks if the average size of each previous promotion to the old age (since it is uncertain how many objects will survive that time, so take the previous average/experience value) is greater than the remaining size of the old age, and if so, performs a Full GC instead. If less, check whether the HandlePromotionFailure setting allows guarantee failure; If allowed, only Minor GC will be performed; If not, do a Full GC instead. Averaging is still a dynamic probability method, meaning that if the number of objects surviving a Minor GC is significantly higher than the average, it will still result in Handle Promotion Failure, which triggers a Full GC.

Garbage collection algorithm classification

2.1 reference

2.2 GC Root objects

2.3 Mark — Sweep

It is regarded as the ideological basis of modern garbage recycling algorithms.

  Mark-clear algorithmScanning from the root set is adopted to mark the surviving objects. After marking, unmarked objects in the whole space are scanned for recycling, as shown in the figure above. The mark-clear algorithm does not need to move objects and only processes the non-viable objects, which is extremely efficient in the case of a large number of viable objects. However, because the mark-clear algorithm directly reclaims the non-viable objects, it will cause memory fragmentation.

2.4 Copying Algorithms

This algorithm is proposed to overcome the overhead of handle and solve the garbage collection of heap fragments. Build on the premise of fewer live objects and more garbage objects. This algorithm only processes objects that are in use each time, so the replication cost is relatively small, and the corresponding memory can be reorganized after the replication, and there will be no fragmentation problem. But the disadvantage is also obvious, that is, it requires twice the memory space.

It starts by dividing the heap into one object surface and several free surfaces. The program allocates space for objects from the object surface. When the objects are full, garbage collection based on the copying algorithm scans the live objects from the root set and copies each live object to the free surface (leaving no free holes between the memory occupied by the live objects). So the free plane becomes the object plane, the original object plane becomes the free plane, and the program allocates memory in the new object plane. A typical stop-and-copy algorithm based on the coping algorithm divides the heap into object planes and free area planes, and the program suspends execution during the switch.

2.5 Mark-Collation (or mark-compression algorithm, Mark-Compact, or MarkSweepCompact)

This algorithm combines the advantages of “mark-clean” and “copy algorithm”. The fragmentation problem of “mark-clean” is avoided, and the space problem of “copy” algorithm is also avoided.

The mark-collation algorithm marks objects in the same way as the mark-clear algorithm, but the clearing is different. After the space occupied by the non-viable objects is reclaimed, all the viable objects are moved to the left free space and the corresponding Pointers are updated. Mark-tidy algorithm is based on mark-clear algorithm, but also carries on the object movement, so the cost is higher, but it solves the problem of memory fragmentation. In the implementation of a collector based on the Compacting algorithm, handles and handle tables are typically added.

2.6 Generational Collecting Strategy

Based on the fact that the life cycle of different objects is different. Therefore, different recycling algorithms can be adopted for objects with different life cycles in order to improve the recycling efficiency.

Since the objects of the new generation have a short survival time and need frequent GC, the replication algorithm with high efficiency is adopted. The memory is divided into one Eden region and two Suvivor regions. By default, the ratio between Eden region and survivor region is 8:1. Gc is performed using a replication algorithm that copies surviving objects to a survivor zone, copies its surviving objects to another zone when a survivor zone is full, and puts the object into the old age when it lives longer than a certain threshold. The old and permanent generations, because of their long lifetime of living objects, use the tag cleanup or tag cleanup algorithm

Conclusion:

  • New generation: replication algorithm (new generation of recycling frequency is very high, every recycling time is very short, in order to support the new generation of high frequency recovery, virtual machine can use a data structure called the Card sheet (Card Table), Card tables for a collection of bits that each bit can be used to represent the old s whether all objects in the hold of a field of new generation of,

2.7 Garbage collector

Garbage collectorThe task of garbage collector is to identify and reclaim garbage objects for memory cleaning. Different generations can use different collectors:

  • Collector used by the new generation collector: Serial, ParNew, Parallel Scavenge;
  • Serial Old (MSC), Parallel Old, CMS

Conclusion:

  1. Serial Old and new generation of all recyclers can be matched; Can also be used as a backup collector for CMS collector;
  2. CMS can only work with Serial and ParNew of the new generation, and ParNew is the default new generation collector of CMS.
  3. Parallel: Multiple garbage collection threads work in Parallel while the user thread is still in a waiting state
  4. Concurrent: The execution of both the user thread and the garbage collector thread at the same time (but not necessarily in parallel, possibly alternately), with the user program continuing to run while the garbage collector is running on another CPU.

Iii. GC execution mechanism

The heap (DEAP) in Java is also the primary area for GC garbage collection. Because objects are processed in generations, garbage collection regions and times are different. There are two types of GC: Scavenge GC (Minor GC) and Full GC (Major GC).

  • Scavenge GC(Minor GC): Normally, when a new object is generated (age=0) and Eden fails to apply for space, the Scavenge GC is triggered to clean up the Eden exploiture, and the surviving objects are moved to a Survivor zone (age+1). Then organize the two Survivor zones. In this way, GC is performed on the Eden area of the young generation without affecting the old generation. Since most objects start from Eden, and Eden is not allocated very large, GC in Eden will occur frequently. Therefore, a fast and efficient algorithm (copy-clean algorithm) is generally needed to make Eden free as soon as possible. Most objects in Java generally do not live long and are ephemeral in nature.
  • Full GC:

Clean up the entire heap, including Young, Tenured, and Perm. Full GC is slower than Scavenge due to the need to recycle the entire pair, so minimize the amount of Full GC you do. A large part of the process of tuning the JVM is tuning FullGC.

3.1 Scenarios that trigger Full GC execution

3.2 Young GC trigger condition

3.3 New object GC Recall process

Based on the assumption that most newborn objects are reclaimed in the GC. The new generation GC uses the replication algorithm, (the young generation is divided into three parts, mainly to keep the objects with short life cycle in the young generation as much as possible. The older generation mainly stores objects with a long lifetime, such as caches). Possible experience:

  1. When an object is created, memory allocation is usually done in Eden (special cases).
  2. When Eden area is full, minorGC will be triggered to collect garbage in Young (Eden +1survivor) area because the space cannot be applied for when creating objects.
  3. At minorGC, the Eden and Survivor A objects that cannot be retrieved by GC and whose ages do not reach the tenuring threshold are placed into Survivor B, always ensuring that one survivor is empty;
  4. As in step 3, if survivor is found to be full, copy these objects to the old section (allocation guarantee mechanism); Or survivor is not full, but some objects are Old enough to be placed in the Old section XX:MaxTenuringThreshold; (Review the age of the object)
  5. Clear Eden and survivor A directly;
  6. When the Old block is full, fullGC is performed.

3.4 the GC log

Parameters related to GC logs:

  • -xx :+PrintGC: prints GC logs
  • -xx :+PrintGCDetails: Prints GC details logs
  • -xx :+PrintGCTimeStamps: prints GC timestamps (in base time)
  • – XX: + PrintGCApplicationStoppedTime: print recycling program suspended during the period of time
  • – XX: + PrintGCApplicationConcurrentTime: print before each garbage collection, the execution time of the procedure not interrupt
  • -xx :+PrintHeapAtGC: Prints heap information before and after GC
  • -xx :+PrintTLAB: Displays the usage of TLAB space
  • – XX: PrintTenuingDistribution: check the new survival after each minor GC cycle threshold
  • -xx :PrintReferenceFC: tracks soft references, weak references, and virtual references in the system, and displays the reference process

Case study: – XX: XX: + PrintGCApplicationStoppedTime – + PrintGCApplicationConcurrentTime used together

    Application time: 0.3440086 seconds
    Total time for which application threads were stopped: 0.0620105 seconds
    Application time: 0.2100691 seconds
    Total time for which application threads were stopped: 0.0890223 seconds
Copy the code

Knowing that the application was actually working for the first 344 milliseconds, then suspending all threads for 62 milliseconds, then working for another 210ms, and then for another 89ms.

2796146K->2049K(1784832K)] 4171400K->2049K(3171840K), [Metaspace: 3134K->3134K(1056768K)], 0.0571841 secs] [Times: User =0.02 sys=0.04, real=0.06 SECs] Total time for which application threads were stopped: Stopping Threads took: 0.0000088 secondsCopy the code

The application thread was forced to pause for 57ms for garbage collection. Another 8ms is spent waiting for all application threads to reach the safe point.

Setting -xx :+PrintGCDetails will automatically bring -verbose: GC and -xx :+PrintGC

33.125: [GC [DefNew: 3324K->152K(3712K, 0.0025925secs] 3324K->152K(11904K, 0.0031680secs] 100.667: [Full GC [Tenured: 0K->210K(10240K), 0.0149142 secs] 4603K->210K(19456K), [Perm: [Times: user= 0.03sys =0.00, real= 0.03secs] [Times: user= 0.03sys =0.00, real= 0.03secs]Copy the code
  1. The leading numbers “33.125:” and “100.667:” represent the time when GC occurred, which is the number of seconds that have elapsed since the Java Virtual machine started.
  2. The “[GC” and “[Full GC” at The beginning of The GC log indicate The type of pauses for The garbage collection, not to distinguish between The new generation GC and The old GC. If there is “Full”, it indicates that stop-the-world GC occurred.
  3. The following “[DefNew”, “[Tenured”, and “[Perm” indicate the region in which GC will take place. The names shown here are closely related to the GC collector being used. For example, in the Serial collector used in the example above, the New Generation is called “Default New Generation”. So the display is “[DefNew”. If it is a ParNew collector, the New Generation name will change to “[ParNew”, meaning “Parallel New Generation”. The Parallel Insane, the new generation to which it is derived, is called the PSYoungGen. The older generation is named the same way as the permanent generation.
  4. The value 3324K->152K(3712K) in the square brackets indicates used capacity of the memory region before GC -> Used capacity of the memory region after GC (total capacity of the memory region). “3324K->152K(11904K)” outside square brackets means “Used capacity of the Java heap before GC -> Used capacity of the Java heap after GC (total capacity of the Java heap)”.
  5. After that, “0.0025925 secs” indicates the amount of time, in seconds, that this memory region takes to GC. Some collectors give more specific time data
  6. [Full GC 283.736: [ParNew: 261599K->261599K, 0.0000288 secs]

The new generation collector, ParNew, will also have a “[Full GC” log (usually due to issues such as allocation guarantee failure, which causes STW). If the collection is triggered by a call to the system.gc () method, “[Full GC (System)” will appear here.

3.5 Measures to reduce GC overhead

From the code:

Tuning from JVM parameters:

3.6 Classification of Memory overflow

Summary -JVM tuning related

4.1 Purpose of Tuning

.

4.2 Level of JVM performance tuning

4.3 JVM Tuning Process

4.4 Performance Monitoring Tool

The ultimate goal of tuning is to allow applications to carry more throughput with minimal hardware consumption. The SAME applies to JVM tuning, which focuses on the collection performance optimization of the garbage collector to enable applications running on virtual machines to use less memory and latency to achieve greater throughput.

Is everyone still ok? If you like, move your hands to show 💗, point a concern!! Thanks for your support!

Welcome to pay attention to the public number [Ccww technology blog], original technical articles launched at the first time