This article is participating in “Java Theme Month – Java Debug Notes Event”, see < Event link > for more details.

One, foreword

Java Virtual Machine (JVM for short) is the most core thing in The Java language. Java programs cannot run without it. Because of its existence, Java has the characteristics of “once compiled, many times run”. Bytecode files (.class) can run on any platform that has a Java virtual machine specific to that platform.

The JVM is one of the most difficult and important knowledge points in Java. It is often used to measure a person’s basic Java skills and is one of the most frequently asked questions in interviews. This article will start with the Java Virtual Machine memory model and walk through it step by step.

The Java Virtual Machine memory model is the basis on which Java programs run. To make Java applications run properly, the JVM divides its memory data into program counters, virtual machine stacks, local method stacks, heaps, and method areas, as shown in the following figure:

(since JDK1.8, the concept of a method area has been removed and Metaspace replaced it.)

Program counter is used to store the next run instruction; The virtual machine stack and the local method stack are used to store function method call stack information. The Java heap is used to store objects and other data required by Java programs when they run. The method area is used to hold metadata information for the program.

Some of these are thread private and some are thread shared.

  • Thread private: program counters, virtual machine stacks, local method stacks
  • Thread sharing: heap, method area

Second, program counter

A program counter is a small memory space that holds the next instruction to run. It is thread private and can be considered a line number indicator for the current thread.

Since Java is a thread-enabled language, when the number of threads exceeds the number of cpus, threads poll for CPU resources based on time slices. With a single-core CPU, only one thread can be running at any one time, and other threads must be switched out. To do this, each thread must record an instruction to run with a separate program counter. The counters between each thread do not affect each other and work independently.

If a thread is executing a Java method, the program counter records the Java bytecode address being executed, and if the current thread is executing a Native method, the program counter is empty.

Iii. Virtual Machine Stack (stack)

The stack holds the local variables and partial results of the method, and participates in the call and return of the method, namely: stack frame data.

1. The stack frame

When each method is executed, a stack frame is created to store information about local variables, operand stacks, dynamically linked methods, return addresses, and so on. Each method called corresponds to a stack frame in the virtual machine stack from the push (method call) to the push (method return) process.

The stack frame structure is shown in the figure below:

If the method is called with a relatively large number of parameters and local variables, the local variables in the stack frame will be large, and the stack frame will be very large. Therefore, the stack space required for a single method call will also be large. (Try to avoid this when developing programs, especially in recursive methods to avoid the depth of recursive calls)

In the following code snippet, a StackOverflowError is thrown by progressively setting the depth of recursive method calls.

Public class StackTest {private final int count = 100000; Public void recursionMethod(int num) {num++; if (num < count) { recursionMethod(num); } } @Test public void stackDepthTest() { recursionMethod(0); }}Copy the code

2. Stack overflow or memory overflow

The Java Virtual Machine specification allows stack sizes to be dynamic or fixed, and defines two types of exceptions related to stack space: StackOverflowError and OutOfMemoryError. StackOverflowError is raised if the stack depth requested by the thread is greater than the maximum available stack depth during calculation, or OutOfMemoryError is raised if the stack can scale dynamically and there is not enough memory to support stack scaling during the process.

Among other things, the JVM parameter -xSS can be used to adjust the size of the setup stack, which determines the depth that method calls can reach.

In the above code StackTest, when the recursion times is 100000, the -xss parameter is adjusted to -xss512m and no exception is thrown.

3. Jclasslib tools

As a side note, I still feel it is necessary to mention that when studying THE JVM, we will always study some bytecode instructions, Class file structure, size and other data, and jClasslib tools just meet these requirements, with it helps us to have a deeper understanding of Java, JVM.

We can choose to install according to their preferences, there are stand-alone software version, IDE plug-in for use, here, I choose to install jclasslib plug-in in IDEA, easy to use. This tool will take you on a journey through the JVM world.

As shown in the figure below, check stackTest. class file in idea through jclasslib plug-in. Expand method recursionMethod, check Misc TAB of Code attribute, the current method’s maximum local variable table capacity is 2. Because there is only one parameter of type int in this method, it takes two words.

For more tips on how to use the Jclasslib tool, feel free to continue using it.

Local method stack

The function of the local method stack is similar to that of the virtual machine stack, which is used to manage calls to Java methods, and the local method stack, which is used to manage calls to local methods.

The native methods are not implemented in Java, but in C. The native method stack holds the information of the native method. When a thread created by a JVM calls the Native method, the JVM no longer creates stack frames for it in the virtual machine stack. The JVM simply dynamically links and directly calls the Native method.

In Hot Spot virtual machines, there is no distinction between the local method stack and the virtual machine stack. Therefore, the local method stack also throws stackOverflowErrors and OutofMemoryErrors.

Five, the heap

The heap is arguably the most important part of Java runtime memory, and almost all objects and arrays are allocated in the heap. The heap is divided into the new generation and the old generation. The new generation is used to store the newly generated objects and the young objects. If the objects are not recovered and survive long enough, the old objects will be moved to the old generation.

The new generation can be further subdivided into Eden, survivor space0(s0 or from space), and survivor space1(s1 or to space). Eden calls it the Garden of Eden, the birthplace of objects, where most objects are stored when they are first created. S0 and S1 are survivor Spaces, meaning that objects stored in them have survived at least one garbage collection. If the object in the surviving zone has not been collected by the specified age, it has a chance to enter the old age.

In other words, the heap space is simply divided into new generation and old generation, where the new generation is used to store the newly created objects and the old generation is used to store the older objects (objects that have been in the heap for a long time and have been garbage collected more times).

The heap space structure is shown in the figure below:

6. Method area

The method area, like the heap, is an area of memory shared by all threads and is called non-heap to distinguish the heap. The main information stored is the class metadata, i.e., class type information, constant pool information, domain information, method information, such as static modified variables are loaded into the method area when the class is loaded.

The type information includes the full name of the class, the full name of the parent class, the type modifier (public/protected/private), and the direct interface class table of the type. The constant pool contains constant information referenced by the class method, field, and so on; Domain information includes domain name, domain type, and domain modifiers. The method information includes the method name, return type, method parameters, method modifiers, method bytecode, local variable area size of operand stack and method frame stack, and exception table. In general, most of the information stored in the method area comes from class files.

In the Hot Spot VIRTUAL machine, the method area also becomes a permanent area, a piece of memory separate from the Java heap. Although called a permanent section, objects in a permanent section can also be collected by GC. It just behaves a little differently for GC than for Java heap space. The collection of permanent GC is usually analyzed from two aspects: one is the collection of permanent GC to the constant pool, the other is the collection of permanent GC to the class metadata.

The method area has also become a permanent area, where constants and class definition information are stored.

(in the JDK1.8 HotSpot virtual machine, the method area concept has been removed and replaced with Metaspace, and it has been moved to local memory planning.)