1. Runtime data area

The Java virtual machine defines several run-time data areas that are used by programs while they are running, some of which are created when the virtual machine is started and destroyed when the virtual machine exits. Others are thread-specific, with thread-specific data areas created and destroyed as threads start and end.

According to the Java Virtual Machine Specification, the memory managed by the Java Virtual Machine will include the following runtime data areas:

1.1 program counter

The Program Counter Register, also known as the PC Register, is a small piece of memory.

It can be thought of as a line number indicator of the bytecode being executed by the current thread. In the conceptual model of Java virtual machine, bytecode interpreter works by changing the value of this counter to select the next bytecode instruction to be executed. It is an indicator of program control flow, and basic functions such as branch, loop, jump, exception handling and thread recovery depend on this counter.

Each Java virtual machine thread has its own program counter. At any given time, a Java virtual machine thread executes code for only one method, and the method being executed by the thread is called the current method of that thread

If the method is not native, the PC register holds the address of the bytecode instructions being executed by the Java VIRTUAL machine. If the method is native, the VALUE of the PC register is undefined.

1.2. Java Virtual Machine stack

Like program counters, the Java Virtual Machine Stack is thread-private and has the same life cycle as a thread. The virtual machine Stack describes the threaded memory model of Java method execution: When each method is executed, the Java VIRTUAL machine synchronously creates a Stack Frame to store information about local variables, operand stacks, dynamic connections, method exits, and so on. The process of each method being called and executed corresponds to the process of a stack frame moving from the virtual machine stack to the virtual machine stack.

Java memory areas can be roughly divided into Heap and Stack memory, where the “Stack” usually refers to the virtual machine Stack in this case, or more often just the local variable scale portion of the virtual machine Stack.

The local variable table stores various Java virtual machine basic data types (Boolean, byte, CHAR, short, int, float, long, double) and object references (reference type, which is not the same as the object itself) known at compile time. May be a reference pointer to the object’s starting address, a handle representing the object or other location associated with the object) and the returnAddress type (which points to the address of a bytecode instruction).

The storage space of these data types in the local variable table is represented by local variable slots, where 64-bit long and double data types occupy two variable slots and the rest occupy only one. The memory space required for the local variable table is allocated at compile time. When entering a method, how much local variable space the method needs to allocate in the stack frame is completely determined, and the size of the local variable table does not change during the method run.

The following exceptions may occur on the Java VIRTUAL machine stack:

  • The Java virtual machine will throw a StackOverflowError if the stack size allocated by the thread request exceeds the maximum size allowed by the Java virtual machine stack.

  • The Java virtual machine will throw an OutOfMemoryError if the Java virtual machine stack can be dynamically extended, and the extension has been attempted, but there is currently not enough memory to complete the extension, or there is not enough memory to create the corresponding virtual machine stack when a new thread is created.

1.3. Local method stack

The role of Native Method Stacks is very similar to that of the virtual machine stack, except that the virtual machine stack performs Java methods (i.e. bytecodes) for the virtual machine, whereas the Native Method stack services the Native methods used by the virtual machine.

The Java Virtual Machine specification allows native method stacks to be implemented as fixed size or dynamically expanded and contracted based on computation.

The following exceptions may occur in the local method stack:

  • The Java virtual machine will throw a StackOverflowError if the stack size allocated by thread requests exceeds the maximum size allowed by the local method stack.

  • The Java virtual machine will throw an OutOfMemoryError if the local method stack can be extended dynamically, and the extension has been attempted, but there is currently not enough memory to complete the extension, or there is not enough memory to create the corresponding local method stack when a new thread is created.

1.4, the Java heap

For Java applications, the Java Heap is the largest chunk of memory managed by the virtual machine. The Java heap is an area of memory that is shared by all threads and is created when the virtual machine is started. The sole purpose of this memory area is to hold object instances, and “almost” all object instances in Java are allocated memory here.

The Java Heap is an area of memory managed by the Garbage collector, so it is also referred to as the “GC Heap” (Garbage Collected Heap) in some sources. From the perspective of reclaimed memory, since most modern garbage collectors are designed based on generational collection theory, Java heap often has terms such as “new generation”, “old generation”, “permanent generation”, “Eden space”, “From Survivor space”, “To Survivor space”, etc. It is important to note that these partitions are only a common feature or design style of a subset of garbage collectors, not the inherent memory layout of a particular Java VIRTUAL machine implementation, nor any further refinement of the Java heap in the Java Virtual Machine Specification.

From the perspective of memory Allocation, the Java heap shared by all threads can be allocated with multiple Thread private Allocation buffers (TLabs) to improve the efficiency of object Allocation. However, no matter what the perspective is, no matter how it is divided, it does not change the commonality of what is stored in the Java heap. No matter what region is stored, it can only store instances of objects. The purpose of subdividing the Java heap is to recycle memory better, or to allocate memory faster.

According to the Java Virtual Machine Specification, the Java heap can be in a physically discontinuous memory space, but logically it should be considered contiguous, just as we use disk space to store files without requiring each file to be contiguous. But for large objects (typically groups of objects), most virtual machine implementations will most likely require contiguous memory space for simplicity of implementation and storage efficiency.

The Java heap can be implemented as either fixed size or extensible, but most current Java virtual machines are implemented as extensible (with the -xmx and -xms parameters). The Java virtual machine will throw an OutOfMemoryError if there is no memory in the Java heap to complete the instance allocation and the heap can no longer be extended.

1.5. Method area

The Method Area, like the Java heap, is an Area of memory shared by threads that stores data such as type information that has been loaded by the virtual machine, constants, static variables, and code caches compiled by the just-in-time compiler. Although the Java Virtual Machine Specification describes the method area as a logical part of the Heap, it has an alias called “non-heap” to distinguish it from the Java Heap.

The Java Virtual Machine Specification is very relaxed about method areas, and in addition to the fact that the Java heap does not require continuous memory and can be either fixed size or extensible, you can even choose not to implement garbage collection. Garbage collection is relatively rare in this area, but it is not the case that data enters the method area as “permanent” as the name of the permanent generation. The target of memory reclamation in this area is mainly for constant pool reclamation and type unloading. Generally speaking, the reclamation effect in this area is not satisfactory, especially for type unloading, but the reclamation in this part of the area is indeed necessary sometimes. Several of the most serious bugs on Sun’s previous Bug list were memory leaks caused by earlier versions of the HotSpot VIRTUAL machine not fully reclaiming this area.

According to the Java Virtual Machine Specification, OutOfMemoryError is thrown if the method area cannot meet the new memory allocation requirements.

It’s worth noting that many people prefer to refer to methods as “Permanent Generation,” or lump the two together. The two are not essentially equivalent, as it was only the HotSpot VIRTUAL machine design team that chose to extend the generational design of the collector to the method area, or to implement the method area using persistent generations, which allowed the HotSpot garbage collector to manage this part of memory as well as the Java heap. Save the effort of writing memory-management code specifically for the method area. However, for other virtual machine implementations, such as BEA JRockit, IBM J9, etc., there is no concept of permanent generation.

1.6. Runtime constant pool

The Runtime Constant Pool is part of the method area. The Constant Pool Table is used to store various literals and symbolic references generated at compile time. This part of the Table is stored in the runtime Constant Pool of the method area after the Class is loaded.

The Java VIRTUAL machine has strict rules on the format of each part of the Class file (including the constant pool). For example, each byte must meet the requirements of the specification to store the data before the VIRTUAL machine accepts, loads, and executes the data. However, for the runtime constant pool,

The Java virtual machine specification does not make any detail requirement, different providers implement a virtual machine can according to their own needs to realize this memory area, but in general, in addition to save Class files described in symbolic reference, also be to translate by symbols refer to the direct reference is also stored in the runtime constants in the pool.

Runtime constant pool relative to the Class file another important feature of the constant pool is dynamic, the Java language does not require constant Must only compile time to produce, that is to say, is not a preset constant pool into the Class file content can enter method area runtime constant pool, runtime can also be new constants in the pool, One feature that developers use most often is the Intern () method of the String class.

Since the runtime constant pool is part of the method area and is naturally limited by the method area memory, OutOfMemoryError is thrown when the constant pool can no longer claim memory.

1.7. Direct memory

Direct Memory is not part of the run-time data area of the virtual machine, nor is it defined in the Java Virtual Machine Specification.

The NIO (New Input/Output) class was introduced in JDK 1.4, introducing a Channel and Buffer based I/O method that can allocate off-heap memory directly using Native libraries. This is then referenced by a DirectByteBuffer object stored in the Java heap. This can significantly improve performance in some scenarios because it avoids copying data back and forth between the Java heap and Native heap.

Obviously, the allocation of native direct memory is not limited by the Size of the Java heap. However, since it is memory, it is certainly limited by the size of the total native memory (including physical memory, SWAP partition, or paging file) and the addressing space of the processor. Parameters such as -xmx are set according to the actual memory, but the direct memory is often ignored. As a result, the sum of each memory area is greater than the physical memory limit (including the physical and operating system level limit), resulting in OutOfMemoryError during dynamic expansion.

2, JDK memory region changes

2.1. Jdk1.6/1.7/1.8 Memory area changes

As mentioned in the previous section, the HotSpot virtual machine is the default Java virtual machine in the Sun/OracleJDK and OpenJDK, and is the most widely used implementation of the JVM. As mentioned above, the Java VIRTUAL machine specification is very lax on the method area, and HotSpot VIRTUAL machine has some bugs in this area, so HotSpot method area has undergone some changes. Let’s take a look at the changes in HotSpot VIRTUAL machine memory area.

  • The JDK1.6 era is consistent with the JVM memory region we discussed above:

  • In JDK1.7 something changed to put a pool of string constants, static variables, on the heap

  • In JDK1.8, the method area was completely eliminated, and an area of direct memory was set aside as a meta-space, into which the runtime constant pool and class constant pool were moved.

2.2. Why is the method area replaced

Why was the method area replaced? Of course, or is it more accurate to say that what is permanently replaced? The method areas specified by the Java Virtual Machine specification are simply implemented in a different way. There are objective and subjective reasons.

  • The objective design of using persistent generations to implement method section decisions makes Java applications more prone to memory overflow problems (persistent generations have -xx: MaxPermSize, which has a default size even if not set, while J9 and JRockit are fine as long as they don’t touch the upper limit of the process’s available memory, such as the 4GB limit on 32-bit systems.), And there are very few methods (such as String:: Intern ()) that behave differently on different VMS due to persistent generation.

  • Subjectively, when Oracle acquired the ownership of JRockit by acquiring BEA, it tried to transplant the excellent functions in JRockit, such as Java Mission Control management tool, to HotSpot VIRTUAL machine, but faced many difficulties due to the difference in method area implementation between the two. Considering the future development of HotSpot, in JDK 6 the HotSpot development team planned to abandon the permanent generation and gradually adopt Native Memory to implement the method area. In JDK 7 HotSpot, In JDK 8, the concept of permanent generation was completely abandoned and replaced with meta-spaces implemented in local memory like JRockit and J9. In JDK 8, the concept of permanent generation was replaced with meta-spaces implemented in local memory like JRockit and J9. Move all of the remaining content of the persistent generation in JDK 7 (mainly type information) into the meta space.





Reference:

[1] : Zhou Zhipeng, In Depth Understanding the Java Virtual Machine: Advanced JVM Features and Best Practices

[2] : Zhou Zhipeng et al translated Java Virtual Machine Specification

[3] : Memory section: JVM memory structure

[4] : This time, finally learned the JVM memory structure systematically

[5] : Face manual · Chapter 25 summary of JVM memory model, there are JDK comparison, there are OOM monitoring cases in meta space, there are Java version of virtual machine, comprehensive learning is easier!