Runtime data area

During the execution of Java programs, the Java virtual machine divides the memory it manages into several different data areas, often referred to as runtime data areas. Java prides itself on automatic memory management compared to manual memory management in C and C++.

In the JVM, THE JVM memory is divided into heap, method area, program counter, virtual machine stack, and local method stack.

At the same time, according to the relationship between threads can also be divided as follows:

1) Thread private area: a thread has a separate memory area.

2) Thread shared area: shared by all threads, and only one copy.

There is also direct memory (off-heap memory), which is not part of the runtime data area but is used frequently. It can be understood as other memory on an operating system that is not virtualized. For example, if you have 8 gigabytes of memory on the operating system and 3 gigabytes virtualized by the JVM, you have 5 gigabytes of memory left, which the JVM uses with some tools. This portion of memory is called direct memory.

The virtual machine stack

Function: Stores the data, instructions, and return address required by the current thread to run a Java method.

The virtual stack is thread-based and runs in the same lifecycle as the program, even if there is only one main method.

By default, the virtual machine stack size is 1 MB. Adjust the size with -xss, for example, -xss256K.

Refer to the official documentation (JDK1.8) : docs.oracle.com/javase/8/do…

Stack Frames: Each time a Java method is called, a stack frame is created and merged into the stack. Once the method completes the corresponding call, the stack is removed.

The stack frame generally contains the following four areas:

1) Local variable table: used to store local variables (variables in the method). First of all, it is a 32-bit length, which mainly stores the eight basic data types of Java. Generally, it can be stored in 32 bits, and if it is 64 bits, it can use high and low bits to occupy two data types. If it is some local objects, such as our Object Object, We just need to store a reference address to it.

2) Operand stack: The operand stack is used to store the operands performed by Java methods. As the name implies, it is used for operations. The operands can be any Java data type, so when a method starts, the operand stack is empty. Essentially, the operand stack is a workspace for the JVM’s execution engine, meaning that operations on the operand stack are performed while methods are executing; otherwise, the operand stack is empty.

3) Dynamic linking: Java language features polymorphisms (more on this in the following sections, need to be combined with the class and execution engine).

4) Return address: return normally (address in the calling program counter as return), exception (determined by the exception handler table < > in the non-stack frame).

Program counter

Action: Points to the address of the bytecode instruction being executed by the current thread.

A program counter is a small memory space that is used to record the addresses of bytecodes executed by individual threads. For example, branches, loops, jumps, exceptions, thread recovery, and so on all depend on the counter. Because Java is a multithreaded language, when the number of threads executing exceeds the number of CPU cores, threads compete for CPU resources based on time slice polling. If a thread runs out of time or is robbed of CPU resources prematurely for other reasons, the exiting thread needs a separate program counter to record a running instruction.

Because the JVM is a virtual machine, it has a complete set of instructions and execution process, so when running Java methods, you need to use program counters (which record the address or line number of the bytecode execution). If you encounter native methods, this method is not executed by the JVM. This is because there is also a program counter at the operating system level that records the address of the execution of the native code, so the value of the program counter in the JVM is null (Undefined) when the native method is executed.

Note: The program counter is also the only memory area in the JVM that is not OOM (OutOfMemory).

Local method stack

The local method stack is similar to the Java virtual machine stack, which is used to manage calls to Java functions, and the local method stack, which is used to manage calls to local methods. But native methods are not implemented in Java, but in C (such as the Object.hashcode method).

The native method stack is an area very similar to the virtual machine stack that serves native methods. You can even think of the virtual machine stack and the local method stack as the same area. It is not mandated by the VIRTUAL machine specification and can be implemented on all versions of the virtual machine. HotSpot directly blends the local method stack with the virtual machine stack.

Methods area

The method area is used to store information about classes that have been loaded by VMS, including class information, static variables, constants, runtime constant pool, and string constant pool.

The method area is a “logical partition” of memory by the JVM. Prior to JDK1.7 and earlier, many developers used the term “persistent generation” because in the HotSpot virtual machine, designers used persistent generation to implement the method area of the JVM specification. In JDK1.8 and later, meta-spaces were used to implement method areas.

When the JVM executes a class, it must be loaded first. When a class is loaded (loading, validating, preparing, parsing, and initializing), the JVM first loads a class file. The class file contains information about the class version, fields, methods, and interfaces, as well as the Constant Pool Table. Used to hold various literal and symbolic references generated during compilation.

Literals include strings (String a= “b”), constants of primitive types (final modified variables), and symbolic references include fully qualified names of classes and methods (for example, the String class, Its fully qualified name is Java/lang/String), the field name and descriptor, and the method name and descriptor.

Symbolic reference

When a Java class (let’s say People) is compiled into a class file, if People references the Tool class, but at compile time People does not know the actual memory address of the referenced class, so symbolic references are used instead.

When the People class is loaded by the class loader, the real memory address of the Tool class can be obtained from the virtual machine. Therefore, the symbol org.simple.Tool can be replaced with the real memory address of the Tool class, and the address can be directly referenced.

That is, a symbolic reference is used to replace the reference class at compile time and the virtual machine obtains the actual address of the reference class at load time.

A set of symbols describing the referenced object, which can be any literal, as long as it is used unambiguously to locate the object. Symbolic references are independent of the memory layout implemented by the virtual machine, and the target of the reference is not necessarily already loaded into memory.

Constant pools versus runtime constant pools

When a class is loaded into memory, the JVM stores the contents of the class file’s constant pool into the runtime constant pool. During the parsing phase, the JVM replaces symbolic references with direct references (the index value of the object).

For example, a string constant in a class file is stored in the class file constant pool. After the JVM loads the class, the JVM puts the string constant into the runtime constant pool and, during the parsing phase, specifies the index value of the string object. The runtime constant pool is shared globally. Multiple classes share the same runtime constant pool. Only one copy of the same string in the constant pool will exist in the class file.

Constant pools have many concepts, including runtime constant pools, class constant pools, and string constant pools.

Strictly speaking, the static constant pool holds string literals, symbol references, and class and method information, and the runtime constant pool holds runtime direct references. Run-time constant pooling is the transfer of symbolic reference values from the static constant pool to the run-time constant pool after the class is loaded. After the class is parsed, symbolic references are replaced with direct references.

After JDK1.7, the runtime constant pool was moved to heap memory, which is the physical space and still logically belongs to the method area (which is the logical partition).

dimension

The method area, like the heap space, is also a shared memory area, so the method area is shared by threads. If two threads are trying to access the same class information in the method area, and the class has not yet been loaded into the JVM, only one thread is allowed to load it, and the other thread must wait.

In the HotSpot virtual machine, the pool of static variables and runtime constants for the persistent generation has been moved to the heap in the Java7 release, the rest is stored in the JVM’s non-heap memory, and the Java8 release has removed the persistent generation implemented in the method area. The previous persistent generation is replaced with class metadata, which is stored in local memory.

Method area size parameter:

  • JDK1.7 and earlier (initial and maximum) : -xx :PermSize; -XX:MaxPermSize
  • After JDK1.8 (initial and maximum) : -xx :MetaspaceSize; -XX:MaxMetaspaceSize

After JDK1.8, the size is only limited by the total native memory (if no parameter is set)

Why does Java8 use meta-spaces instead of persistent generations, and what are the benefits of doing so?

Official explanation: The removal of permanency is an effort to merge HotSpot JVM with JRockit VM, as JRockit does not have permanency, so it is not necessary to configure permanency. Memory often enough or permanent generation of memory, an exception is thrown. Java lang. OutOfMemoryError: PermGen. This is because in JDK1.7, the size of the specified PermGen area is 8M. Since metadata information of classes in PermGen may be collected in each FullGC, the recovery rate is always low, and the results are hardly satisfactory. It is also difficult to determine how much space to allocate for PermGen. The size of PermSize depends on many factors, such as the total number of classes loaded by the JVM, the size of the constant pool, and the size of the methods.

The heap

The heap is the largest area of memory on the JVM, where almost all of the objects we request are stored. When we say garbage collection, the object of operation is the heap. Heap space is usually claimed at startup, but not always used. The heap is typically set up to be scalable.

As objects are created frequently, the heap space becomes more and more occupied, and objects that are no longer in use need to be irregularly reclaimed. This is called Garbage Collection (GC) in Java.

When an object is created, is it allocated on the heap or on the stack?

This has to do with two things: the type of the object and its location in the Java class.

Java objects can be divided into ** basic data types and ordinary objects. ** For normal objects, the JVM first creates the object on the heap and then uses its references elsewhere. For example, store this reference in a local variable table in the virtual machine stack.

For basic data types (byte, short, int, long, float, double, char), there are two cases. When you declare an object of primitive data type in the method body, it is allocated directly on the stack. In other cases, it’s all on the heap.

Heap size parameter:

  • -Xms: indicates the minimum value of the heap
  • -Xmx: indicates the maximum value of the heap
  • -XMN: Cenozoic size
  • -xx :NewSize: indicates the minimum value of the new generation
  • -xx :MaxNewSize: indicates the maximum value of the new generation

Direct memory (off-heap memory)

When the JVM is running, it requests large chunks of heap memory from the operating system for data storage. There is also the virtual machine stack, the local method stack, and the program counter, called the stack area. The remaining memory of the operating system is also known as out-of-heap memory.

It is not part of the run-time data area of the virtual machine, nor is it an area of memory defined in the Java Virtual Machine specification; If NIO is used, this area is frequently used and can be directly referenced and manipulated within the Java heap using directByteBuffer objects; This memory is not limited by the Java heap size, but is limited by the total native memory, which can be set by -xx :MaxDirectMemorySize (the default is the same as the maximum heap memory), so an OOM exception will occur.

Summary:

1. Direct memory is mainly the memory obtained by DirectByteBuffer. MaxDirectMemorySize can be used to limit its size.

2. Other out-of-heap memory, mainly refers to memory directly applied for using Unsafe and other JNI methods.

Out-of-heap memory leakage is very serious, it is difficult to troubleshoot, impact, and even cause the death of the host. Also, note that Oracle previously planned to remove the sun.misc.Unsafe API from Java9. One of the reasons sun.misc.Unsafe is removed here is to make Java more secure, and there are alternatives.