Learn more about Java basics
Does the Class information in the Java Virtual Machine specification method area, also known as the persistent generation, belong to the Java heap? JVM internals (I) – Overview
Run-time Data Areas
The Java virtual machine defines various runtime data areas that are used during program execution. Some of these data areas are created when the Java virtual machine is started and destroyed only when the Java virtual machine exits. The other data areas are per-thread. Thread data areas are created when threads are created and destroyed on thread exit. The JVM manages several run-time data areas: the method area, the virtual machine stack, the local method stack, the heap, and the program counter, where the method area and heap are data areas shared by threads, and the others are thread-isolated data areas. Program counters, virtual machine stacks, local method stacks, thread dependent, thread dead.
Thread exclusive
- Program counter
- The virtual machine stack
- Local method stack
Threads share
- The heap
- Methods area
Program counter /PC counter (The PC Register)
A program counter is a small piece of memory that can be thought of as an indicator of the line number executed by the current thread. Each Java virtual machine thread has its own program counter, which is usually increased after the execution of an instruction, so it needs to hold the address of the next instruction to be executed. The bytecode interpreter works by changing the value of this counter to select the next bytecode instruction to be executed. Branch, loop, jump, exception handling, thread recovery and other basic functions need to be completed by this counter. If the thread is executing a Java method, this counter records the address of the virtual machine bytecode instruction being executed. This counter is empty if the Native method is being executed. This memory region is the only one where the Java Virtual Machine specification does not specify any OutOfMemotyError cases
Java Virtual Machine Stacks
Each thread has its own stack, which holds each method executed within the thread in the form of a frame. The stack is a last in, first out (LIFO) data structure, so the currently executing method is at the top of the stack. Each time a method is called, a new frame is created and pushed to the top of the stack. When a method normally returns or throws an uncaught exception, the frame is either removed from the top of the stack. There are no direct operations on the stack other than pushing and removing frame objects, so frame objects are allocated in the heap and memory is not required to be continuous. For the execution engine, only the stack frame at the top of the stack is valid in the active thread, called the current stack frame, and the method associated with this stack frame is called the current method. All bytecode instructions run by the execution engine operate only on the current stack frame. In the Java Virtual Machine specification, two exceptions are specified for the virtual machine stack: a StackOverflowError is thrown if the stack depth of a thread request is greater than the depth allowed by the virtual machine; If the virtual stack can scale dynamically (and most Java virtual machines currently do, although the Java Virtual Machine specification also allows fixed-length virtual stacks), an OutOfMemoryError will be thrown when sufficient memory cannot be allocated while scaling.
The Frame (Frame)
Each time a method is called, a new frame is created and pushed to the top of the stack. Frames are unstacked when a method returns normally or throws an uncaught exception. Detailed Exception handling is described in the Exception Table section below.
Every frame is included
- Local variables
- Return value
- Operand stack
- Dynamic Linking
Local variable
A local variable table is a set of variable value storage Spaces for method parameters and local variables defined within a method. When the Java program is compiled into a Class file, the max_locals data item of the method’s Code property determines the maximum local variable table capacity that the method needs to allocate. The Java virtual machine uses local variables to pass parameters on method calls. In class method calls, any arguments are passed in successive local variables starting with local variable 0. In instance method calls, the local variable 0 is always used to pass a reference to the object on which the instance method was called (this in the Java programming language). Any arguments are then passed in successive local variables starting with local variable 1.
Local variables can be:
- Boolean operand stack
- byte
- char
- long
- short
- int
- float
- double
- reference
- returnAddress
All types occupy one slot in the local variable array, while long and double occupy two consecutive slots because they have double widths (64-bit instead of 32-bit). The virtual machine specification does not specify the length of the Reference type, but in general, virtual machine implementations should at least be able to find, directly or indirectly, the starting address index of the object in the Java heap and object type data in the method area from this reference. The returnAddress type is for bytecode instructions JSR, JSR_W, and RET services and points to the address of a bytecode instruction.
Operand stack
Each frame contains a LIFO stack, called its operand stack. The maximum depth of a frame’s operand stack is determined at compile time and supplied with the code for the frame-related methods. The virtual machine uses the operand stack as its workspace — most instructions pop data from here, perform operations, and then push the results back into the operand stack. For example, iadd pops two integers from the operand stack, performs an addition operation, and pushes the result back into the operand stack. Look at the following example, which shows how the virtual machine adds two local variables of type INT and saves the result to a third local variable:
begin
iload_0 // push the int in local variable 0 ontothe stack
iload_1 //push the int in local variable 1 onto the stack
iadd // pop two ints, add them, push result
istore_2 // pop int, store into local variable 2
end
Copy the code
In this bytecode sequence, the first two instructions, ILoAD_0 and ILoAD_1, push the integers indexed 0 and 1 stored in local variables into the operand stack, and the iADD instruction adds the two integers from the operand stack and pushes the result into the operand stack. The fourth instruction, istore_2, pops the result from the operand stack and stores it at index 2 in the local variable area. The following figure details the state changes of local variables and operand stacks during this process, with unused areas of local variables and operand stacks represented by blank Spaces.
The return address
Method return is divided into two cases, one is normal exit, after exit, the method definition will decide whether to pass the return value to the upper layer of the caller, one is the exception caused by the end of the method, in this case, the return value will not be passed to the upper layer of the calling method.
If the method exits normally, the value of the caller’s PC counter can be used as the return address. If the method exits abnormally, it needs to be determined by the exception handling table.
Method of a call corresponds to the stack frame in a virtual machine stack into the stack operation, so the method exits can do include: to restore the upper method local variables and the operand stack, if the return value is the return value to the caller in the frame of the operand stack, also the PC counter value is adjusted for method calls the entrance to the next instruction.
Dynamic Linking
As the virtual machine runs, the runtime constant pool stores a large number of symbolic references, which can be viewed as indirect references to each method. If represents the stack frame of A way to call on behalf of the stack frame B method, then the method of virtual machine call instruction will with symbols of the B method reference as A parameter, but because A symbolic reference is not directly represent the B method of memory locations, so before the call must also convert symbolic reference to reference directly, You can then access the actual method by direct reference.
If symbolic references are converted to direct application during class loading or the first time they are used, the conversion becomes static resolution, and if converted to direct reference at run time, the conversion becomes dynamic join.
Native Method Stack
The role of the Native method stack is very similar to that of the virtual machine stack, except that the virtual machine stack performs Java method (that is, bytecode) services for the virtual machine, while the Native method stack serves the Native methods used by the virtual machine. The virtual machine specification does not mandate the language, usage, or data structure of methods in the local method stack, so specific virtual machines are free to implement it. There are even virtual machines (such as the Sun HotSpot VIRTUAL machine) that simply merge the local method stack with the virtual machine stack.
Like the virtual stack, the local method stack area throws StackOverflowError and OutOfMemoryError exceptions.
Heap (Heap)
The heap is where the runtime allocates class instances and array memory. Arrays and objects cannot be stored on a stack because a stack frame is not designed for this purpose. Once a stack frame is created, its size cannot be changed. Frames are used only to store references to objects or arrays in the pair. Unlike the basic variables and references in the array of local variables within a frame, objects are always stored in the heap, so they are not removed before the method ends. Furthermore, objects can only be removed by the garbage collector.
To support the garbage collection mechanism, the heap is typically divided into three parts:
- Young Generation
- They are usually classified as new Eden and Survivor.
- Old Generation/Tenured Generation
- Permanent Generation (removed in JDK8)
Memory Management
Objects and arrays are not explicitly removed, but are automatically reclaimed by the GC. The usual order is this:
- New objects and arrays are created in the new generation area
- Small GCS occur in the Cenozoic, and surviving objects are moved from Eden to Survivor.
- A large GC usually causes application threads to pause and object movement to occur between generations. Objects that are still alive are moved from the new generation to the old.
- The collection time of the permanent generation will always occur when collecting on the old generation. When any generation runs out of memory, a collection occurs at the same time.
For more details on the New generation, old age, and GC, please check out the subsequent articles on JVM Learning
Method Area
This article focuses on the method area. Because the implementation of the method area permanent generation has been changed in JDK6,7, and 8 respectively.
Method Area introduction
In the JVM virtual machine specification:
The Java Virtual Machine has a method area that is shared among all Java Virtual Machine threads. The method area is analogous to the storage area for compiled code of a conventional language or analogous to the “text” segment in an operating system process. It stores per-class structures such as the run-time constant pool, field and method data, and the code for methods and constructors, Including the special methods (§2.9) used in class and instance initialization and interface Initialization. The method area is created on virtual machine start-up. Although the method area is logically part of the heap, simple implementations may choose not to either garbage collect or compact it. This specification does not mandate the location of the method area or the policies used to manage compiled code. The method area may be of a fixed size or may be expanded as required by the computation and may be contracted if a larger method area becomes unnecessary. The memory for the method area does not need to be contiguous. A Java Virtual Machine implementation may provide the programmer or the user control over the initial size of the method area, as well as, in the case of a varying-size method area, control over the maximum and minimum method area size.
In a Java virtual machine, a Method Area is an Area of runtime memory that can be shared by threads. The method section acts much like the Storage Area Of Compiled Code or Text egment Of an operating system process in a traditional language in that it contains structural information about each class. Examples include the Runtime Constant Pool, field and method data, bytecode content for constructors and common methods, and special methods for class, instance, and interface initialization.
The method area is created when the virtual machine is started, and while the method area is a logical part of the heap, a simple virtual machine implementation can choose not to implement garbage collection in this area. This version of the Java Virtual Machine specification also does not limit the memory location of the implementation method area or the management policy for compiled code. The capacity of a method area can be a fixed size, or it can expand dynamically as the program executes and automatically shrink when no more space is needed. Method areas can be discontinuous in real memory space.
Java virtual machine implementations should provide programmers or end users with the means to adjust the initial capacity of a method area, or to adjust its maximum or minimum capacity if it can be dynamically expanded and contracted
If the memory space of the method area does not meet the memory allocation request, the Java virtual machine will throw an OutOfMemoryError.
In short, it is used to store the structural information of the class. It has an alias called non-heap.
The permanent generation
The persistent generation is an implementation of the method area in HotSpot. PermGen space is often referred to as a method area. It makes sense to understand this in a certain way. Because the JVM virtual machine specification only specifies the concept of a method area and what it does, it does not specify how to implement it. Then, the implementation of the method area must be different on different JVMS. Also, most of the JVMS used are Sun’s HotSpot. In HotSpot, GC generation collection is extended to the method area, or the method area is implemented using persistent generation.
It is, though, a stretch to explain this equating view of method zones with permanent zones. But the final method zone is different from the permanent zone. One is the standard and one is the implementation.
Permanent generation prior to JDK1.7
Prior to java7, the method area was located in PermGen, which is isolated from the heap and whose size can be set to a fixed, immutable value when the JVM is started. Here is a question that is often asked in interviews: the string.Intern () method. For details, read the following article: Java Basics: String — String Constant Pool and Intern (2)
Permanent generation of JDK1.7
In Highlights of Technology Changes in Java SE 7, we can see that
In JDK 7, interned strings are no longer allocated in the permanent generation of the Java heap, but are instead allocated in the main part of the Java heap (known as the young and old generations), along with the other objects created by the application. This change will result in more data residing in the main Java heap, and less data in the permanent generation, and thus may require heap sizes to be adjusted. Most applications will see only relatively small differences in heap usage due to this change, but larger applications that load many classes or make heavy use of the String.intern() method will see more significant differences.
In JDK 7, Interned Strings are no longer allocated in the permanent generation of the Java heap, but in the main part of the Java heap (called young and old) along with other objects created by the application. This change will result in more data in the main Java heap and less data in the permanent generation, so you may need to resize the heap. Because of this change, most applications will see a relatively small difference in heap usage, but large applications that load many classes or use the String.Intern () method heavily will see a more significant difference.
And does the Class information of the method area, also known as the permanent generation, belong to the Java heap? Medium, R big explanation:
Oracle JDK7 / OpenJDK 7 HotSpot VM moves Symbol storage from PermGen to native memory. And move the static variable from the end of instanceKlass (within PermGen) to the end of the java.lang.class object (within the normal Java heap). Constant pool = Runtime constant pool = Runtime constant pool If “constant pool” is SymbolTable/StringTable, the tables themselves are always in native memory, so it’s more interesting where they reference things. As mentioned above, 7 moves the Symbol referenced by SymbolTable to native memory, and the java.lang.String instance referenced by StringTable is moved from PermGen to the normal Java heap.
Runtime constant pool SymbolTable and String constant pool As a result, we can see that in Java 7, some of the data stored in the permanent generation has been moved to the Java Heap or Native Memory. However, persistent generations are still present in JDK 1.7 and have not been completely removed.
Jdk1.8 meta space and permanent generation
In JEP 122: Remove the Permanent Generation
Move part of the contents of the permanent generation in Hotspot to the Java heap and the remainder to native memory.
Hotspot’s representation of Java classes (referred to here as class meta-data) is currently stored in a portion of the Java heap referred to as the permanent generation. In addition, interned Strings and class static variables are stored in the permanent generation. The permanent generation is managed by Hotspot and must have enough room for all the class meta-data, interned Strings and class statics used by the Java application.
The proposed implementation will allocate class meta-data in native memory and move interned Strings and class statics to the Java heap. Hotspot will explicitly allocate and free the native memory for the class meta-data. Allocation of new class meta-data would be limited by the amount of available native memory rather than fixed by the value of -XX:MaxPermSize, whether the default or specified on the command line.
- PermGen is removed and Metaspace is replaced.
- Class metadata in the permanent generation is moved to native memory (local memory, not virtual machine).
- Interned Strings and Class Static variables from the permanent generation have been moved to the Java Heap;
- Permanent generation parameter (PermSize MaxPermSize) -> MetaspaceSize MaxMetaspaceSize
In java8, the permanent generation is removed and the method area is stored in Metaspace, which is still disconnected from the heap but shares physical memory with the heap and is logically considered to be in the heap.
Why remove the permanent generation?
- Strings exist in persistent generation, which is prone to performance problems and memory overflow.
- The permanent generation size is not easy to determine, PermSize too small may cause permanent generation OOM
- Persistent generation introduces unnecessary complexity to the GC and is inefficient for collection.
- Oracle may merge HotSpot with JRockit.
Direct memory
Direct memory is not part of the runtime data area of the virtual machine, nor is it defined in the Java Virtual Machine specification. NIO class is a channel – and buffer-based I/O approach. It can use Native libraries to allocate out-of-heap memory directly, and then operate with a DirectByteBuffer object stored in the Java heap as a reference to that direct memory. This avoids copying data back and forth between the Java heap and the Navie heap