(In-depth understanding of the Java virtual machine) An article takes you to learn the various areas of the Java virtual machine memory

I. Introduction

For developers who are engaged in the development of C and C++ programs, in the field of memory management, they are both the "emperor" with the highest authority and the working people engaged in the most basic work-both having the "ownership" of each object, and Responsible for the maintenance of each subject's life from beginning to end.

For Java programmers,With the help of the automatic memory management mechanism of the virtual machine, it is no longer necessary to write paired delete/free code for each new operation, and it is not easy to cause memory leaks and memory overflow problems, It seems that everything is fine when the virtual machine manages the memory.

However, it is precisely because Java programmers give the power to control memory to the Java virtual machine. Once memory leaks and overflow problems occur, if you don’t understand how the virtual machine uses memory, troubleshooting and correcting the problem will be Become an extremely difficult job.

Two, runtime data area

The Java virtual machine divides the memory it manages into several different data areas during the execution of the Java program. These areas have their own purposes, and the time of creation and destruction. Some areas always exist as the virtual machine process starts, and some areas are created and destroyed depending on the start and end of the user thread.
According to the "Java Virtual Machine Specification", the memory managed by the Java Virtual Machine will include the following runtime data areas:

Insert picture description here

Three, the program counter

The Program Counter Register is a small memory space, which can be regarded as a line number indicator 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.

Since the multi-threading of the Java virtual machine is implemented by thread switching and allocating processor execution time in turn, at any certain moment, a processor (a core for a multi-core processor) will only execute one Instructions in the thread
Therefore, in order to restore to the correct execution position after thread switching, each thread needs to have an independent program counter. The counters between the threads do not affect each other and are stored independently. We callThis type of memory area is "thread private" memory

If the thread is executing a Java method, this counter records the address of the executing virtual machine bytecode instruction; if the thread is executing a Native method, the counter value should be undefined. This memory area is the only one without any provision in the "Java Virtual Machine Specification" in the OutOfMemoryErrorregional context

Fourth, the 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 (Stack Frame) to store information such as local variable tables, operand stacks, dynamic connections, and method exits.The process of each method being called until the execution is completed corresponds to the process of a stack frame in the virtual machine stack from the stack to the stack

Some people often divide the Java memory area into heap memory (Heap) and stack memory (Stack). This division method directly inherits the memory layout structure of traditional C and C++ programs. It appears a bit rough in the Java language. The actual memory area division is more complicated than this.

However, the popularity of this division indirectly shows that the areas that programmers are most concerned about and are most closely related to object memory allocation are the "heap" and "stack". among them,The "stack" usually refers to the virtual machine stack mentioned here, or more often just the local variable table part of the virtual machine stack.

The local variable table stores the basic data types (boolean, byte, char, short, int, float, long, double) and object references (reference type, which is not equivalent to the object itself, which can be known at compile time). It is a reference pointer to the starting address of the object, or it may point to a handle representing the object or other locations related to this object) and returnAddresstype (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. . Please note that the "size" mentioned here refers to the number of variable slots, how much memory space the virtual machine really uses (for example, according to a variable slot occupies 32 bits, 64 bits, or more) to realize a variable slot , This is completely determined by the specific virtual machine implementation.

In the "Java Virtual Machine Specification", two types of abnormal conditions are specified for this memory area: if the stack depth requested by the thread is greater than the depth allowed by the virtual machine, StackOverflowErroran exception will be thrown ; if the stack capacity of the Java virtual machine can be dynamically expanded, when When the stack is expanded, OutOfMemoryErroran exception will be thrown if sufficient memory is not available .

Five, the 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" does not have any mandatory provisions on the language, usage and data structure of the methods in the local method stack. Therefore, the specific virtual machine can freely implement it as needed, and even some Java virtual machines (such as Hot-Spot Virtual machine) directly combines the local method stack and the virtual machine stack into one. Like the virtual machine stack, the local method stack will also throw StackOverflowError and OutOfMemoryError exceptions respectively when the stack depth overflows or the stack expansion fails.

Six, 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 the Java world allocate memory here

The description of the Java heap in the "Java Virtual Machine Specification" is: "All object instances and arrays should be allocated on the heap", and the "almost" written by the author here means that from an implementation perspective, with the development of the Java language, we can now see some signs that support for value types may appear in the future, even if we only consider now, due to the just-in-time compilation technology The progress of, especially the increasingly powerful escape analysis technology, stack allocation, scalar replacement [illustration] optimization methods have caused some subtle changes to happen quietly, so that Java object instances are allocated on the heap and gradually become less absolute .

The Java heap is a memory area managed by the garbage collector, so it is also called "GC heap" in some materials (Garbage Collected Heap, fortunately, it is not translated into "garbage heap" in China). 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”. What I want to explain here is that these area divisions are only the common features or design styles of some garbage collectors, not the inherent memory layout implemented by a Java virtual machine. It is not a further detailed division of the Java heap in the "Java Virtual Machine Specification".
Many materials often say something like "The heap memory of the Java virtual machine is divided into young generation, old generation, permanent generation, Eden, Survivor...". Ten years ago (with the emergence of the G1 collector as the demarcation), as the industry's absolute mainstream HotSpot virtual machine, its internal garbage collectors were all designed based on "classic generation", requiring the combination of new and old generation collectors In this context, the above statement is not too ambiguous. But today, the garbage collector technology is not the same as ten years ago. There are also new garbage collectors that do not adopt generational design in HotSpot. There are many points to be discussed according to the above formulation.

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 how divided, it will not change the commonality of the contents of the Java heap. No matter which area, it can only store object instances. The purpose of subdividing the Java heap is only for better recycling. Memory, or allocate memory faster. In this chapter, we only discuss the role of the memory area. The details of the allocation and recovery of the above-mentioned areas in the Java heap will be the subject of the next chapter.

According to the "Java Virtual Machine Specification",The Java heap can be in a physically non-contiguous memory space, but logically it should be regarded as continuous. This is like we use disk space to store files. It does not require that every file is stored continuously.. But for large objects (typically array objects), most virtual machine implementations are likely to require contiguous memory space for the sake of simplicity and storage efficiency.

The Java heap can be implemented as a fixed size or expandable, but the current mainstream Java virtual machines are all implemented according to scalability (set by 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.

Seven, 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 JIT 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.

Speaking of the method area, I have to mentionThe concept of permanent generation, especially before JDK 8, many Java programmers are accustomed to developing and deploying programs on the HotSpot virtual machine. Many people prefer to call the method area "Permanent Generation", or the two Confuse

In essence, the two are not equivalent, because the HotSpot virtual machine design team at that 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. In principle, how to implement the method area belongs to the implementation details of the virtual machine, which is not governed by the "Java Virtual Machine Specification" and does not require uniformity. But looking back now, the decision to use the permanent generation to implement the method area was not a good idea. This design made Java applications more likely to encounter memory overflow problems (permanent generation has the upper limit of -XX: MaxPermSize, even if not The setting also has a default size, and as long as J9 and JRockit do not touch the upper limit of the available memory of the process, such as the 4GB limit in a 32-bit system, there will be no problems), and there are very few methods (for example String::intern()) due to permanent generation. This leads to different performances under different virtual machines. 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 due to the differences in the method area between the two. Taking into account the future development of HotSpot, in JDK6, the HotSpot development team abandoned the permanent generation and gradually changed to the plan to use native memory to implement the method area. By the HotSpot of JDK 7, it has already placed the original in the permanent generation. The string constant pool, static variables, etc. were moved out, and in JDK 8, the concept of permanent generation was finally completely abandoned. Instead, the meta-space implemented in local memory like JRockit and J9 was used instead. The remaining content (mainly type information) of the permanent generation in 7 is all moved to the meta space.

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.However, 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 relatively 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 not fully reclaiming this area and causing memory leaks. According to the "Java Virtual Machine Specification", if the method area cannot meet the new memory allocation requirements, OutOfMemoryErroran exception will be thrown .

Eight, runtime constant pool

Runtime Constant Pool is part of the method area. In addition to the description information of the class version, fields, methods, interfaces, etc. 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 compilation. 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 needs, but generally speaking, except Classfor the description in the save file In addition to the symbolic references, the direct references translated from the 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 during compilation, that is to say, the content of the constant pool that is not preset into the Class file can be entered. Method area runtime constant pool, you can also put new constants into the pool during runtime. This feature is used by developers more often in the String class intern()method. 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, OutOfMemoryErroran exception will be thrown .

Nine, direct memory

Direct Memory is not a part of the data area of ​​the virtual machine runtime, nor is it the memory area defined in the "Java Virtual Machine Specification". But this part of the memory is also frequently used, and it may also cause OutOfMemoryErrorexceptions, so we will explain it here.

In JDK 1.4, the NIO (New Input/Output) class was newly added, and an I/O method based on Channel and Buffer 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 direct memory allocation of the machine will not be limited by the Java heap size, but since it is memory, it will definitely be affected by the total memory of the machine (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), which causes an OutOfMemoryErrorexception during dynamic expansion .

Guess you like

Origin blog.csdn.net/nanhuaibeian/article/details/109070608