[JVM Advanced Road] Two: Java memory area

1. Runtime data area

The Java virtual machine defines several runtime data areas that will be used during the running of the program, some of which are created when the virtual machine is started, and destroyed when the virtual machine exits. Others have a one-to-one correspondence with threads, and these data areas corresponding to threads will be created and destroyed as the 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:

Java virtual machine runtime data area

1.1, program counter

The Program Counter Register, also known as the PC register, is a small memory space.

It can be seen as an indicator of the line number of the bytecode executed by the current thread. In the conceptual model of the Java virtual machine, when the bytecode interpreter works, it selects the next bytecode instruction to be executed by changing the value of this counter. It is an indicator of program control flow, branching, looping, and jumping. Basic functions such as exception handling, thread recovery, etc. all need to rely on this counter to complete.

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

If this method is not native, then the PC register stores the address of the bytecode instruction being executed by the Java virtual machine. If the method is native, then the value of the PC register is undefined.

1.2, Java virtual machine stack

Like the program counter, the Java Virtual Machine Stack (Java Virtual Machine Stack) is also thread-private, and its life cycle is the same as that of a thread. The virtual machine stack describes the thread memory model of Java method execution: when each method is executed, the Java virtual machine will synchronously create a stack frame to store local variable tables, operand stacks, dynamic connections, and methods. Export and other information. The process from when each method is called to the completion of execution corresponds to the process of a stack frame from pushing to popping in the virtual machine stack.

Java virtual machine stack

The Java memory area can be roughly divided into heap memory (Heap) and stack memory (Stack), where "stack" usually refers to the virtual machine stack mentioned here, or more often just refers to the local variables in the virtual machine stack Table part.

The local variable table stores the basic data types (boolean, byte, char, short, int, float, long, double) of the Java virtual machine known at compile time, and object references (reference types, which are not equivalent to the object itself, it may It is a reference pointer to the starting address of the object, or it may be a handle representing the object or other locations related to this object) and the returnAddress type (pointing to the address of a bytecode instruction).

The storage space of these data types in the local variable table is represented by a local variable slot (Slot), where 64-bit long and double data will occupy two variable slots, and the remaining data types will only occupy one. The memory space required by the local variable table is allocated during compilation. When entering a method, how much local variable space this method needs to allocate in the stack frame is completely determined, and the size of the local variable table will not be changed during the running of the method. .

The following exceptions may occur in the Java virtual machine stack:

  • If the stack capacity allocated by the thread request exceeds the maximum capacity allowed by the Java virtual machine stack, the Java virtual machine will throw a StackOverflowError exception.

  • If the Java virtual machine stack can be dynamically expanded, and the expansion action has been tried, but currently cannot apply for enough memory to complete the expansion, or there is not enough memory to create the corresponding virtual machine stack when creating a new thread, then Java The virtual machine will throw an OutOfMemoryError exception.

1.3, local method stack

Native method stacks (Native Method Stacks) and virtual machine stacks play very similar roles. The difference is that the virtual machine stack serves the virtual machine to execute Java methods (that is, bytecode), while the native method stack serves the virtual machine. Native method service used by the machine.

The Java virtual machine specification allows the native method stack to be implemented as a fixed size or dynamically expanded and contracted based on calculations.

The following exceptions may occur in the local method stack:

  • If the stack capacity allocated by the thread request exceeds the maximum capacity allowed by the local method stack, the Java virtual machine will throw a StackOverflowError exception.

  • If the local method stack can be dynamically expanded, and the expansion action has been tried, but currently cannot apply for enough memory to complete the expansion, or there is not enough memory to create the corresponding local method stack when creating a new thread, then Java Virtual The machine will throw an OutOfMemoryError exception.

1.4, Java heap

For Java applications, the Java Heap is the largest piece of memory managed by the virtual machine. The Java heap is a memory area shared by all threads and is created when the virtual machine starts. The sole purpose of this memory area is to store object instances, and "almost" all object instances in Java allocate memory here.

The Java heap is a memory area managed by the garbage collector, so it is also called "GC heap" (Garbage Collected Heap,) in some materials. From the perspective of reclaiming memory, since most modern garbage collectors are designed based on generational collection theory, there are often "new generation", "old generation", "permanent generation", "Eden space", and "From Survivor" in the Java heap. Nouns such as “Space” and “To Survivor Space”. It should be noted that these area divisions are just some of the common features or design styles of garbage collectors, not the inherent memory layout implemented by a Java virtual machine, not to mention the "Java The Java Heap is further divided in detail in the Virtual Machine Specification.

Java heap memory structure

From the perspective of memory allocation, the Java heap shared by all threads can be divided into multiple thread-private allocation buffers (Thread Local Allocation Buffer, TLAB) to improve the efficiency of object allocation. However, no matter from any angle, no matter what the division, it will not change the commonality of the storage content in the Java heap. No matter which area, the storage can only be the instance of the object. The purpose of subdividing the Java heap is only for better recycling. Memory, or 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 regarded as contiguous. This is the same as when we use disk space to store files. Each document is required to be stored continuously. But for large objects (typically array objects), most virtual machine implementations are likely to require contiguous memory space for the sake of simple implementation and high storage efficiency.

The Java heap can be implemented as a fixed size or expandable, but the current mainstream Java virtual machines are implemented in accordance with the scalability (set by the parameters -Xmx and -Xms). If there is no memory in the Java heap to complete the instance allocation, and the heap can no longer be expanded, the Java virtual machine will throw an OutOfMemoryError exception.

1.5, method area

The Method Area, like the Java heap, is a memory area shared by each thread. It is used to store data such as type information, constants, static variables, and code cache compiled by the just-in-time compiler that have been loaded by the virtual machine. 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.

Method area

The "Java Virtual Machine Specification" has very relaxed restrictions on the method area. In addition to the same as the Java heap, it does not require contiguous memory and can choose a fixed size or expandable. You can even choose not to implement garbage collection. Relatively speaking, garbage collection is indeed relatively rare in this area, but it is not that the data enters the method area as "permanent" as the name of the permanent generation. The goal of memory recovery in this area is mainly for the recovery of the constant pool and the unloading of types. Generally speaking, the recovery effect of this area is more difficult and satisfactory. Especially for the unloading of types, the conditions are quite harsh, but the recovery of this part of the area is sometimes It is indeed necessary. In the previous Sun company's bug list, several serious bugs that have appeared are due to the low version of the HotSpot virtual machine that did not fully reclaim this area, which led to memory leaks.

According to the "Java Virtual Machine Specification", if the method area cannot meet the new memory allocation requirements, an OutOfMemoryError exception will be thrown.

It is worth mentioning that many people prefer to call the method area "Permanent Generation" or confuse the two. In essence, the two are not equivalent, because the HotSpot virtual machine design team at the time chose to extend the generational design of the collector to the method area, or use permanent generation to implement the method area, which makes HotSpot garbage The collector can manage this part of the memory like the Java heap, saving the work of writing memory management code specifically for the method area. But for other virtual machine implementations, such as BEA JRockit, IBM J9, etc., there is no concept of permanent generation.

1.6, runtime constant pool

Runtime Constant Pool is part of the method area. In addition to the description information of the class version, fields, methods, and interfaces in the Class file, there is also a constant pool table (Constant Pool Table), which is used to store various literal and symbolic references generated during compile time. This part The content will be stored in the runtime constant pool in the method area after the class is loaded.

The Java virtual machine has strict regulations on the format of each part of the Class file (naturally including the constant pool). For example, what kind of data each byte is used to store must meet the requirements of the specification before it can be recognized, loaded and executed by the virtual machine , But for the runtime constant pool,

The "Java Virtual Machine Specification" does not make any detailed requirements. Virtual machines implemented by different vendors can implement this memory area according to their own needs, but generally speaking, in addition to saving the symbol references described in the Class file, they will also Direct references translated from symbolic references are also stored in the runtime constant pool.

Another important feature of the runtime constant pool compared to the class file constant pool is that it is dynamic. The Java language does not require constants to be generated only at compile time, that is, the content of the constant pool that is not preset into the Class file can be entered. The method area is run-time constant pool, and new constants can also be put into the pool during runtime. This feature is used by developers more often in the intern() method of the String class.

Since the runtime constant pool is part of the method area, it is naturally limited by the memory of the method area. When the constant pool can no longer apply for memory, it will throw an OutOfMemoryError exception.

1.7, direct memory

Direct Memory (Direct Memory) is not part of the data area of ​​the virtual machine runtime, nor is it the memory area defined in the "Java Virtual Machine Specification".

In JDK 1.4, the NIO (New Input/Output) class was newly added, and a channel and buffer-based I/O method was introduced. It can use the Native function library to directly allocate off-heap memory, and then Operate by using a DirectByteBuffer object stored in the Java heap as a reference to this memory. This can significantly improve performance in some scenarios because it avoids copying data back and forth between the Java heap and the Native heap.

Obviously, the allocation of native direct memory will not be limited by the size of the Java heap, but since it is memory, it will definitely be affected by the size of the total native memory (including physical memory, SWAP partition or paging file) and processor addressing space When configuring virtual machine parameters, general server administrators will set -Xmx and other parameter information according to the actual memory, but often ignore direct memory, making the sum of each memory area larger than the physical memory limit (including physical and operating system-level Limit), resulting in an OutOfMemoryError exception during dynamic expansion.

2. Changes in the memory area of ​​the JDK

2.1, jdk1.6/1.7/1.8 memory area changes

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

  • The JDK1.6 period is consistent with the JVM memory area we mentioned above:

JDK 1.6 memory area

  • Some changes have taken place in JDK1.7. The string constant pool and static variables are stored on the heap.

JDK 1.7 memory area

  • When JDK1.8 completely kill method area, and an area set aside as a direct memory element space , runtime constant pool of the class constant pool are moved to metaSpace.

JDK 1.8 memory area

2.2. Why replace the method area

Why has the method area been replaced? Of course, or more accurately, why is the permanent generation replaced? ——The method area specified by the Java Virtual Machine Specification is just implemented in another way. There are objective and subjective reasons.

  • Objectively, the design of using the permanent generation to implement the method area decision makes Java applications more likely to encounter the problem of memory overflow (the permanent generation has the upper limit of -XX: MaxPermSize, even if it is not set, there is a default size, and J9 and JRockit as long as they are not touched If you encounter the upper limit of the available memory of the process, such as the 4GB limit in a 32-bit system, there will be no problem), and there are very few methods (such as String::intern()) that will cause different virtual machines to be downloaded due to permanent generation. There are different performances.

  • Subjectively, after Oracle acquired BEA and obtained the ownership of JRockit, it was ready to migrate the excellent features of JRockit, such as the Java Mission Control management tool, to the HotSpot virtual machine, but it faced many difficulties because of the differences in the implementation of the method area between the two. Taking into account the future development of HotSpot, in JDK 6, the HotSpot development team gave up the permanent generation and gradually changed to the plan of using native memory to implement the method area. In HotSpot of JDK 7, the original The permanent generation of string constant pools, static variables, etc. were moved out, and in JDK 8, the concept of permanent generation was finally completely abandoned, and replaced with the meta-space implemented in local memory like JRockit and J9. Move the remaining content (mainly type information) of the permanent generation in JDK 7 to the meta space.




reference:

[1]: "Deep Understanding of Java Virtual Machine: Advanced Features and Best Practices of JVM" by Zhou Zhipeng

[2]: "Java Virtual Machine Specification" translated by Zhou Zhipeng and others

[3]: Memory articles: JVM memory structure

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

[5]: Face-to-face manual · Chapter 25 "JVM memory model summary, there are comparisons of various versions of JDK, meta-space OOM monitoring cases, and Java version virtual machine, comprehensive learning is easier!

Guess you like

Origin blog.csdn.net/sinat_40770656/article/details/115023038