Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”

This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.

Runtime Data Area

The JVM memory model mainly refers to the data area at runtime and consists of five sections, as shown in the following figure.

Virtual machine stack: Also known as method stack, is thread private. For each method executed by a thread, the JVM creates a stack frame in the virtual machine stack to store information about local variables, operation stacks, dynamic links, method exits, and so on. A method is pushed when called, and a method is pushed when returned.

Native method stack: Similar to a stack, it is used to store information about methods executed by threads. The difference is that Java methods are executed using stacks, while native methods are executed using stacks.

Program counter: Holds the bytecode position executed by the current thread. Each thread has a separate counter when working. The program counter serves the execution of Java methods. When native methods are executed, the program counter is empty (Undefined).

The stack, the local method stack, and the program counter are all thread exclusive.

Heap: The largest chunk of memory managed by the JVM. The heap is shared by all threads to house object instances, and almost all object instances are allocated here. An OOM exception is raised when there is no available heap memory. Depending on the lifetime of the object, the JVM manages the heap memory in generations, and the garbage collector manages the collection of objects.

Method area: An area of memory shared by threads, also known as the non-heap area. The permanent generation in JDK 1.7 and Metaspace in JDK 1.8 are implementations of method areas that store information about classes that have been loaded by the virtual machine, constants, static variables, code compiled by the just-in-time compiler, and so on.

Note: When answering this question, answer two main points: one is the function of each part, and the other is which threads are shared and which are exclusive.

Let’s look at these five parts in detail.

1. Vm Stack

The virtual machine stack is also thread-private, synchronized with the life cycle of the thread. In the Java Virtual Machine specification, two exceptions are specified for this area:

  1. StackOverflowError: Raised when the thread request stack depth exceeds the depth allowed by the virtual machine stack.
  2. OutOfMemoryError: Raised when the Java VIRTUAL machine dynamically expands to insufficient memory.

In the process of learning Java virtual machine, we often see a sentence:

The JVM is stack based, while the Dalvik(DVM) is register based.

By “stack-based” I mean the virtual machine stack. The virtual stack was originally intended to describe the memory model of Java method execution. For each method executed by a thread, the JVM creates a stack frame in the virtual stack.

The stack frame

A Stack Frame is a data structure used to support virtual machine method invocation and method execution. Each thread creates a Stack Frame for a method when executing it.

We can think of it this way: a thread contains multiple stack frames, and each stack frame contains local variators, operand stacks, dynamic links, return addresses, and so on.

Local variable scale

The local variable table is the storage space for variable values. The parameters we pass when calling a method, as well as local variables created inside the method, are stored in the local variable table. When Java is compiled into a class file, the max_locals data item in the method’s Code property table determines the maximum local variable table capacity that the method needs to allocate.

Note: local variables are not initialized (both instance variables and class variables are initialized), meaning there is no preparation phase like there is for class variables.

The operand stack

An Operand Stack, also known as an operation Stack, is a LIFO Stack.

As with the local variable table, the maximum depth of the operand stack is written into the max_stacks data item in the method’s Code property table at compile time. The elements in the stack can be any Java data type, including long and double.

When a method is first executed, its operand stack is empty. As the method executes, various bytecode instructions are pushed and ejected from the operand stack (for example, the iADD instruction pops the top two elements of the operand stack, performs addition, and pushes the result back into the operand stack).

Dynamic link

The main purpose of Dynamic Linking is to support Dynamic Linking during method invocation.

In a class file, a method that calls other methods needs to convert symbolic references to those methods into direct references to their memory address, and symbolic references exist in the method area.

In the Java virtual machine stack, each stack frame contains a symbolic reference to the method that the stack belongs to in the runtime constant pool. The purpose of this reference is to support Dynamic Linking during method invocation.

The return address

When a method is executed, there are only two ways to exit the method:

  • Normal exit: The code in a method completes normally, or exits without throwing an exception after encountering a bytecode instruction (such as return) returned by any of the methods.

  • Exception exit: An exception encountered during the execution of a method that is not handled within the method body, causing the method to exit.

No matter how the current method exits, after the method exits, it needs to return to the location where the method was called before the program can continue executing. The “return address” in the virtual machine stack is used to help the current method restore its upper-level method execution state.

In general, when a method exits normally, the caller’s PC count can be used as the return address and may be stored in the stack frame. When the method exits abnormally, the return address is determined by the exception handler table, and this part of information is generally not stored in the stack frame.

2. Native Method Stack

The native method stack is basically the same as the virtual stack described above, except for native methods. It is possible to touch the local method stack more if JNI is involved in development, and in some virtual machine implementations the two are already combined (such as HotSpot).

3. Program Counter Register

Java programs are multithreaded, and the CPU can divide execution time segments among multiple threads. When a thread is suspended by the CPU, it needs to record where the code has been executed, so that the CPU can know which line of instruction to start executing the thread again. That’s what the program counter is for.

A “program counter” is a small memory space in the virtual machine that is used to keep track of where the current thread is executing.

In fact, some familiar thread recovery operations, branches, loops, jumps, exception handling, and so on rely on this counter.

There are a few other things to note about program counters:

  1. The Java Virtual Machine specification does not specify any OutOfMemoryError cases for this area of program counters (perhaps it feels unnecessary).

  2. Thread private. Each thread has a private program counter inside it. Its life cycle is created with the creation of the thread and dies with the end of the thread.

  3. This counter records the address of the virtual machine bytecode instruction being executed when a thread is executing a Java method. If the Native method is being executed, this counter value is null (Undefined).

4. The Heap (Heap)

The Java Heap is the largest area of memory managed by the JVM. Its sole purpose is to hold object instances. Almost all object instances are allocated in the Heap, so it is the primary area managed by the Java Garbage Collector (GC), sometimes called the “GC Heap “.

It is also an area of memory shared by all threads, so objects allocated in this area need to be considered thread safety if they are accessed by multiple threads.

According to the different object storage time, the memory in the heap can be divided into Young generation and Old generation, and the new generation is divided into Eden and Survivor zone. The details are shown in the figure below:

  • Heap space = Cenozoic (1/3)+ Old (2/3)

  • New generation = Eden(8/10)+from(1/10)+to(1/10)

Different areas of the diagram house objects with different life cycles. In this way, different garbage collection algorithms can be used according to different regions, so as to be more targeted and improve garbage collection efficiency.

Ecen area

In most cases, objects will be allocated in Eden of the new generation. When Eden does not have enough space for allocation, the virtual machine will initiate a Minor GC. Minor GC is more frequent and faster than Major GC.

After Minor GC, Eden is cleared, most of the objects in Eden are reclaimed, and the surviving objects that do not need to be reclaimed are placed in Survivor’s From zone (or Old zone if the From zone is insufficient).

Survivor area

The Survivor zone serves as a buffer between the Eden zone and the Old zone, similar to the yellow light in our traffic lights.

Survivor is divided into two zones, one is From zone and one is To zone. Each time a Minor GC is performed, the Eden region and the SURVIVING objects From are placed in the Survivor’s To region (if the To region is insufficient, it goes directly To the Old region).

Survivor exists to reduce the number of objects sent to the old age, thus reducing the incidence of Major GC. Survivor prefilter guarantees that only objects that survive the new generation after 16 Minor GC’s are sent to the old age.

Old district

Older generations occupy two-thirds of The heap and are only cleaned up during Major GC, which triggers “stop-the-world” each time.

The larger the memory, the longer the STW, so it’s not just that bigger memory is better. Because the replication algorithm will carry out many replication operations in the old age when the object survival rate is high, the efficiency is very low, so the mark-collation algorithm is adopted here in the old age.

5. Methods area

The Method Area is also a run-time data Area specified in the JVM specification. The method area mainly stores class information (version, fields, methods, interfaces), constants, static variables, just-in-time compiler compiled code, and data that have been loaded by the JVM. This region, like the heap, is an area of memory shared by individual threads.

Note: Method zones are often confused with “permanent zones” by developers.

So HERE’s a comparison of the two concepts:

  • A method area is an area specified in the JVM specification, but not the actual implementation. It is important not to confuse the specification with the implementation. Different JVM vendors can have different versions of the implementation of the method area.

  • HotSpot used the “permanent section” (or Perm section) to implement the method section prior to JDK 1.7, but the “permanent section” was removed after JDK 1.8 in favor of an implementation called metaspace.

To sum up:

  • A method area is a specification level thing that dictates what data is stored in that area.

  • The permanent section or metaspace is a different implementation of the method section, the implementation level thing.

Memory overflow and memory leak

  • Memory leak: Allocated memory cannot be reclaimed

  • Memory overflow: The system memory is insufficient

Stack overflow

It can be classified as: memory leak and memory overflow, both of which throw OutOfMemoryError.

Memory leaks

A memory leak is a situation in which an object instance is still referenced after being created and used, but cannot be released by garbage collection and accumulates until there is no memory left. If there is a memory leak, we need to find out how the leaked object is referenced by GC ROOT, and then analyze the leak through the reference chain.

Out of memory

Memory overflow is when we create a strength object and the memory required by the instance object is larger than the available space of the heap. If there is a memory overflow problem, it is usually the application needs more memory than we have configured for the virtual machine. In this case, we can use the increase of -xmx to solve the problem.

Stack overflow

The JVM Stack is where Stack frames (local variables, operand stacks, dynamic links, method exit information) are stored. Note the distinction between stacks and stack frames: stacks contain stack frames.

There are two memory exceptions associated with thread stacks:

  • StackOverflowError: Raised when the thread request stack depth exceeds the depth allowed by the virtual machine stack (method call level too deep, not enough memory for new stack frame).
  • OutOfMemoryError: Raised when the Java virtual machine has dynamically expanded to the point where it cannot allocate enough memory (too many threads, not enough memory to create a new thread).

StackOverflowError

Recursive calls are a common scenario for StackOverflowError. So be careful when using recursion.

OutOfMemoryError

Theoretically, outofMemoryErrors can occur in the virtual machine stack, heap, and method area. But in real projects, most of it happens in the heap.

summary

Don’t think of the memory model as a “concrete implementation” of the VIRTUAL machine. There are many concrete implementations of the virtual machine, such as Sun HotSpot, JRocket, IBM J9, and the familiar Android Dalvik and ART. Each of these implementations is implemented in a different way, as long as it conforms to the above five run-time data areas.

The JVM’s runtime memory structure consists of two “stacks” and one “heap” : the Java virtual machine stack and the local method stack, and the “GC heap “and the method area. There is also a program counter (this part is almost never used, so ignore it).

Only the heap and method areas of JVM memory are data areas shared by threads; the rest are thread private. And the program counter is the only area where the Java Virtual Machine specification does not specify any OutOfMemoryError cases.