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

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

Local variables table: The local variables defined in the method and the parameters of the method are stored in this table

Variables in the table of local variables cannot be used directly. If they need to be used, they must be loaded into the operand stack by related instructions as operands

Operand stack: Stores operands on and off the stack

Dynamic Linking: Each stack frame is wrapped with a reference to the method that the stack frame belongs to in the runtime constant pool. This reference is held to support Dynamic Linking during method invocation.

Method return address: Once a method has started execution, there are only two ways to exit, either by encountering bytecode instructions returned by the method or by encountering an exception that is not handled within the method body.

1 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(a){ 
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(a){}public static void main(String[] args){ 
calc(1.2); order(); }}Copy the code

class Person {

.

public static int calc(int, int);

Code:

0: iconst_3 // push int 3 into operand stack

1: istore_0 // store int to [local variable 0]

2: iload_0 // load int value from [local variable 0] onto the stack

3: iloAD_1 // loads int values from [local variable 1] onto the stack

4: iadd // pops the top element off the stack, performs an addition of type int, and pushes the result onto the stack

5: istore_2 // Save the stack top int value to [local variable 2]

6: iloAD_2 // loads int values from [local variable 2] onto the stack

7: ireturn // Returns int data from the method

.

}

The stack to heap

If you have a variable in a stack frame that is of type reference type, such as Object Object = New Object(), this is typically the case when an element in the stack refers to an Object in the heap.

The method area points to the heap

The method area holds static variables, constants, etc. If this is the case, it is typical for an element in the method area to execute objects in the heap

private static Object obj=new Object();

The heap points to the method area

The method area will contain information about the class, there will be objects in the heap, so how do you know which class created the object?

Think: How does an object know which class it was created from? How do I record it? This is where you need to know the details of a Java object

Java object memory layout

An object consists of three parts in memory: object header, instance data, and alignment padding

Memory model:

One is the non-heap area and one is the heap area.

The heap is divided into two large blocks: old and Young.

Young is divided into two blocks: one is Survivor zone (S0 + S1) and the other is Eden zone. Eden: S0: S1 =8:1:1

S0 is the same size as s1, you could call it 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, so which area is an object created in?

The region 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,C, etc. create Eden area, but the memory space of Eden area must be limited, for example, 100M. If 100M has been used or A critical value has been reached, then Eden memory space needs to be cleaned, namely garbage collection. Such GC is called Minor GC. Minor GC refers to the GC in the Young sector

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,

At the same time, only one segment of so and s1 has data 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 objects in the From region will be +1. We know that all living objects in the Eden region will be copied To the To region.

Surviving objects in the From zone have two destinations. If the age of the object reaches the preset age threshold, the object will be moved To the Old area. If the age of the object does not reach the threshold in the Eden area or From area, the object will be 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 in Survivor zone. Since I went to Survivor zone, I have been drifting, sometimes in

Survivor’s “From” zone, sometimes in Survivor’s “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 lived for 20 years (every time

GC plus one year), which is then recycled.

Q&A

1. How to understand Minor GC, Major GC, Full GC

Minor GC: The new generation

Major GC: The old days

Full GC: New generation + old generation

2. Why do WE need Survivor zones? Just Eden?

If there is no Survivor, every time a Minor GC is performed in Eden, and there is no age limit, the surviving objects are 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. Although the frequency of Full GC is reduced, as the space of old age increases, once Full occurs

GC takes longer to execute. 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.

3 why are two Survivor zones needed?

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. The next time Eden is full, the problem arises. Then the Minor GC is performed, and Eden and Survivor each have some surviving objects

The surviving objects are hard placed in the Survivor zone, and it is obvious that the memory occupied by the two parts of the object is not continuous, which 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: S0 8:1:1 in the New generation?

Available memory in the new generation: the copy algorithm guarantees 9:1

Eden: S1 is 8:1 in the available memory

That is, Eden: S1: s2= 8:1:1 in Cenozoic era

Experience and Verification

1) Overflow of heap memory

@RestController 

public class HeapController { 
List<Person> list=new ArrayList<Person>();
 @GetMapping("/heap") 

public String heap(a) 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

2) Method area memory overflow

For example, add class information to the method area

<dependency>
<groupId>asm</groupId>
<artifactId>asm</artifactId>
<version>3.3.1</version>
</dependency>

Copy the code
public class MyMetaspace extends ClassLoader { 

public staticList<Class<? >> createClasses() { List<Class<? >> classes =newArrayList<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); 
}

returnclasses; }}Copy the code
@RestController public class NonHeapController { List<Class<? >> list=newArrayList<Class<? > > ();@GetMapping("/nonheap") public String nonheap(a) 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

The 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]

The virtual machine stack

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

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 StackSpace and explode 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. But the operating system does have a limit on the number of threads in a process

Limited, cannot be generated indefinitely, experience value is around 3000~5000. Thread stack size is a double-edged sword. If set too small, stack overflows can occur, especially if there are recursive, large loops in the thread

Large: If this value is set too large, it will affect the number of stacks to be created. If the application is multi-threaded, it will run out of memory. Welcome to pay attention to the public number: Java treasure to receive more tutorial welfare