preface

Java Virtual Machine knowledge summary of a mind map to share with you:

1. Understand Java virtual machine stacks and stack frames with bytecode instructions

Stack frame: Each stack frame corresponds to a method to be called, which can be understood as the running space of a method. Pay attention to the public number [Procedure yuan Xiaowan] to obtain the atlas.

Each Stack frame includes Local Variables, Operand Stack, A reference to the run-time constant pool, and A method Return address Address) and additional information.

Local variable scale

Local variables defined in a method and its parameters are stored in this table. Variables in a local variable table cannot be used directly. If necessary, they must be loaded into the operand stack by relevant instructions as operands.

The operand stack

Storing operands on and off the stack.

Dynamic link

Each stack frame contains a reference to the method in the runtime constant pool to which that stack frame belongs, which is held to support Dynamic Linking during method invocation.

Method return address

Once a method has started executing, there are only two ways to exit. One is to encounter bytecode instructions returned by the method. One is to encounter an exception that is not handled in the method body.

class Person{ private String name="Jack"; private int age; private final double salary=100; private static String address; private final static String hobby="Programming"; public void say(){ System.out.println("person say..." ); } public static int calc(int op1,int op2){ op1=3; int result=op1+op2; return result; } public static void order(){} public static void main(String[] args){calc(1,2); order(); }}Copy the code
Compiled from "Person.java" class Person { ... public static int calc(int, int); Code: 0: iconst_3 // insert int into [operand stack] 1: istore_0 // insert int into [local variable 0] 2: iload_0 // insert int into [local variable 0] 3: Iload_1 // load int from [local variable 1] into stack 4: Iadd // Pop the top element of the stack, add int, For example, The iadd Instruction (§iadd) adds two int values together. It requires that the int values to be added be the top two values of the operand stack, pushed there by previous instructions. Both of the int values are popped from the operand stack. They are added, and their sum is pushed back onto the operand stack. Subcomputations may be nested on the operand stack, It has an extensive and highly variable property in the spoil.】 5: istore_2 // It has an extensive and highly variable property in the spoil. Iload_2 // load int value from [local variable 2] into stack 7: ireturn // Return int value from method... }Copy the code

2, In-depth analysis

The stack to heap

If you have a variable in a stack frame of type reference type, such as Object obj=new Object(), then it is typical that an element in the stack refers to an Object in the heap.

The method area points to the heap

The method area will store static variables, constants and other data. If this is the case, it is typical that elements in a method area point to objects in the heap.

private static Object obj=new Object();
Copy the code

The heap points to the method area

Methods will contain information about classes, objects will be in the heap, so how do you know which class created the object?

Consider: How does an object know which class it was created from? How do I record it? This requires specific information about a Java object.

Java object memory layout

A Java object consists of three parts in memory: object header, instance data, and alignment padding.

3. Memory model

The illustration

One is the non-heap area and one is the heap area. The heap is divided into two large chunks, one is Old and the other is Young. Young is divided into two blocks: one is Survivor area (S0+S1) and the other is Eden area. Eden:S0:S1=8:1:1 S0 is the same size as S1 and can also be called From or To.

Heap objects and arrays are created to allocate memory space in the Heap. The key is that there are many areas in the Heap. Where is an object created?

Area where the object is created

In general, newly created objects will be allocated to Eden area, and some special large objects will be directly allocated to Old area. For example, objects A, B and C are created in Eden area, but the memory space in Eden area is bound to be limited, for example, 100M. If 100M has been used or reaches A set critical value, Eden’s memory space needs to be cleaned, that is, Garbage Collect. Such GC is called Minor GC, and Minor GC refers to the Young GC.

After GC, some objects will be cleaned up, some objects may still be alive, and the surviving objects will need to be copied to Survivor zone, and then cleared from Eden zone.

Survivor area,

As can be seen From the diagram, Survivor is divided into S0 and S1, which can also be called From and To. Only one region of S0 and S1 has data at the same time, and the other is empty.

Then for the GC above, for example, only Eden and From have objects at first, and To is empty. After a GC operation, the age of the objects in the From area will be +1. We know that all the surviving objects in the Eden area will be copied To the To area, and the surviving objects in the From area will have two destinations.

If the age of an object reaches the preset age threshold, the object is moved To the Old area and 􏰀􏰁Eden􏰂􏰃From􏰂 objects that do not reach the age threshold are copied To the To area. At this point, the Eden area and the From area have been cleared (the GC objects must be gone, and the objects that are not GC have their own places). “From” and “To” switch roles, so “From” becomes “To” and “To” becomes “From”. That is, no matter what, make sure that the Survivor region named To is empty. The Minor GC repeats this process until the To region is filled, and then copies all objects To the old age.

Old district,

From the above analysis, it can be seen that the Old area is generally the object with relatively Old age, or the object with relative exceeding a certain threshold.

There will also be GC operations in the Old region, which we call the Major GC.

Lifetime understanding of objects

I am an ordinary Java object. I was born in Eden district. In Eden District, I saw my little brother who looked like me. One day there were so many people in Eden that I was forced To go To the “From” zone on Survivor. Ever since I went To Survivor zone, I have been drifting, sometimes in Survivor “From” zone, sometimes in Survivor “To” zone, homeless. When I was 18 years old, my father said I was an adult and it was time to go out into the world. So I went to the old generation, the old generation, there are many people, and they are quite old, I know a lot of people here. In the old generation, I live for 20 years (plus one year per GC) and then get recycled.

Q&A

How to understand Minor/Major/Full GC

Minor GC: The new generation

Major GC: The old days

Full GC: New generation + old generation

Why do I need a Survivor zone? Just Eden?

If there is no Survivor, every time a Minor GC is performed in Eden, the surviving object is sent to the old age. As a result, the old age fills up quickly, triggering a Major GC(since Major GC is usually accompanied by Minor GC, it can also be considered Full GC). The old generation has much more memory than the new generation, and a Full GC takes much longer than a Minor GC. What’s the downside of a long execution time? Frequent Full GC takes a long time and can affect the execution and response speed of large programs.

You might say, well, let’s increase or decrease the old space. If the old age space is increased, more living objects can fill the old age. The frequency of Full GC is reduced, but as the old age space increases, it takes longer to execute Full GC once it occurs.

If you reduce the old age space, although the time required for Full GC is reduced, the old age is quickly filled with living objects, and the frequency of Full GC increases.

Therefore, Survivor exists to reduce the number of objects sent to the old age, thus reducing the occurrence of Full GC. The pre-screening of Survivor guarantees that only objects that survive the new generation after 16 Minor GC will be sent to the old age.

Why do YOU need two Survivor zones?

The biggest benefit is that fragmentation is resolved. So why not a Survivor zone? In part 1, we learned that a Survivor zone must be set. Assuming that there is now only one Survivor zone, let’s simulate the flow:

The newly created object is in Eden. Once Eden is full, a Minor GC is triggered and the surviving object in Eden is moved to a Survivor zone. Then the next time Eden is full, the problem will come. At this time, the Minor GC will be performed, and Eden and Survivor will each have some Survivor objects. If Eden and Survivor objects are placed in Survivor area, it will be obvious that the memory occupied by these two objects is discontinuous. This leads to memory fragmentation. There is always a Survivor space that is empty and a non-empty Survivor space that has no fragments.

Why is Eden:S1:S2 8:1:1?

Available memory in the new generation: the memory guaranteed by the replication algorithm is 9:1. Eden:S1 in the available memory is 8:1, that is, Eden:S1:S2 in the new generation = 8:1:1

4, validation,

Heap overflow

Application:

@RestController public class HeapController { List<Person> list=new ArrayList<Person>(); @GetMapping("/heap") public String heap() throws Exception{ while(true){ list.add(new Person()); Thread.sleep(1); }}}Copy the code

Remember to set parameters such as -xmx20m -xMS20m

Running results:

Exception in thread "http-nio-8080-exec-2" java.lang.OutOfMemoryError: GC overhead limit exceeded
Copy the code

Method area memory overflow

For example, add Class information to the method area

Asm dependencies and Class code

<dependency> <groupId>asm</ artifactId> <version>3.3.1</version> </dependency>Copy the code
public class MyMetaspace extends ClassLoader { public static List<Class<? >> createClasses() { List<Class<? >> classes = new ArrayList<Class<? > > (); for (int i = 0; i < 10000000; ++i) { ClassWriter cw = new ClassWriter(0); cw.visit(Opcodes.V1_1, Opcodes.ACC_PUBLIC, "Class" + i, null, "java/lang/Object", null); MethodVisitor mw = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null); mw.visitVarInsn(Opcodes.ALOAD, 0); mw.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); mw.visitInsn(Opcodes.RETURN); mw.visitMaxs(1, 1); mw.visitEnd(); Metaspace test = new Metaspace(); byte[] code = cw.toByteArray(); Class<? > exampleClass = test.defineClass("Class" + i, code, 0, code.length); classes.add(exampleClass); } return classes; }}Copy the code

code

@RestController public class NonHeapController { List<Class<? >> list=new ArrayList<Class<? > > (); @GetMapping("/nonheap") public String nonheap() throws Exception{ while(true){ list.addAll(MyMetaspace.createClasses());  Thread.sleep(5); }}}Copy the code

Set the Metaspace size, for example, -xx :MetaspaceSize=50M. -xx :MaxMetaspaceSize=50M

Running results:

java.lang.OutOfMemoryError: Metaspace at Java. Lang. This defineClass1 (Native Method) ~ [na: 1.8.0 comes with _191] the at Java. Lang. This. DefineClass (763). This Java: ~ [na: 1.8.0 comes with _191] 1 2 3 stack 4.3.1 4.3 virtual machine code demonstrates StackOverFlow public class StackDemo { public static long count=0; public static void method(long i){ System.out.println(count++); method(i); } public static void main(String[] args) { method(1); }}Copy the code

Running results:

Understand and explain

The Stack Space is used to push Stack frames into recursive calls to methods. So when recursive calls get too deep, you can run out of Stack Space and burst StackOverflow errors.

-xSS128K: Sets the stack size for each thread. After JDK 5, the stack size was 1M per thread, and before that, 256K per thread. Adjust the amount of memory required by the thread of the application. Reducing this value generates more threads for the same physical memory. However, the operating system has a limit on the number of threads in a process, which cannot be generated indefinitely. The experience value is about 3000~5000.

Thread stack size is a double-edged sword, if set too small, stack overflow may occur, especially in the thread has a recursive, large loop overflow possibility, if the value is set too large, it will affect the number of stack creation, if the application is multi-threaded, memory overflow errors will occur.

The last

I here organized a Java memory model (JMM) information, Spring family bucket series, Java systematic information (including Java core knowledge, interview topics and the latest 20 years of the Internet, e-books, etc.) friends who need to pay attention to the public number [procedures Yuan Small wan] can obtain.