JVM Chapter 1: Java Runtime Data Area

Table of contents

1. Understand JVM

1.1What is JVM

1.2JRE/JDK/JVM

1.3 Overall structure of JVM

2. Java runtime data area

2.1 Program counter (PC register)

2.2Java Virtual Machine Stacks

2.2.1 Composition of stack frame

2.2.2 Problem analysis

2.2.3 Escape analysis

①Allocation on stack

②Scalar analysis

③Synchronized elimination

2.2.4 Memory overflow

2.2.5 Thread running diagnosis

2.3Native Method Stacks

2.4 piles

2.4.1 Evolution of the heap

2.4.2 Contents of the heap

object instance

String constant pool

static variable

Thread Local Allocation Buffer

2.4.3 Problem analysis

2.4.4 Memory overflow

2.4.5 Heap memory diagnosis

2.5 Method area

2.5.1 The relationship between method area, permanent generation and metaspace

2.5.2 Why should we replace the permanent generation with metaspace?

2.5.3 Contents of method area

①Class information (Klass)

Constant Pool Table

②Runtime Constant Pool

2.5.4 Problem analysis

2.5.5 Characteristics of the method area

2.5.6 Set the size of the method area


1. Understand JVM

1.1What is JVM

JVM is the abbreviation of Java Virtual Machine. It is a fictitious computer that is realized by simulating computer functions on an actual computer. JVM blocks information related to the specific operating system platform. Java programs only The bytecode that needs to be generated to run on the Java virtual machine can run on multiple platforms without modification . When the JVM executes bytecode, it actually ultimately interprets the bytecode into machine instructions for execution on the specific platform.

Virtual machines can be divided into system virtual machines and program virtual machines

  • System virtual machine is a virtualization technology that simulates the entire computer hardware environment, including processors, memory, storage, and external devices. Its main goal is to run multiple operating systems simultaneously on a single physical computer. Each virtual machine has an independent operating system and applications, just like running on a different physical computer. Examples of system virtual machines include VMware, VirtualBox, and Hyper-V.
  • A program virtual machine is a virtualization technology that simulates only a separate application running environment on a computer, rather than the entire operating system. Its main goal is to provide an independent runtime environment that enables applications to run on different operating systems without modification. Program virtual machines are usually used to solve cross-platform compatibility issues and simulate the running environment of an application so that the application can run across platforms. Common program virtual machines include the Java Virtual Machine (JVM).

1.2JRE/JDK/JVM

  • JDK (Java Development Kit) is the core of the entire JAVA, including the Java Runtime Environment JRE (Java Runtime Envirnment), a bunch of Java tools (javac/java/jdb, etc.) and Java-based class libraries (i.e. Java API).
  • JRE (Java Runtime Environment, Java Runtime Environment) is a Java runtime environment. It is a collection of everything needed to run a compiled Java program, mainly including the Java Virtual Machine (JVM) and the Java Basic Class Library (Class Library). JRE is a Java runtime environment, not a development environment, so it does not include any development tools (such as compilers and debuggers)
  • JVM (Java Virtual Mechanal) is a part of JRE, called JAVA virtual machine. It is the core part of the entire Java cross-platform implementation. It is responsible for interpreting, executing and running bytecode files (.class).

1.3 Overall structure of JVM

  • ClassLoader: After the Java code is compiled into a binary, it will go through the class loader so that it can be loaded into the JVM and run.
  • Method Area: Classes are placed in the method area.
  • Heap: instance object of the class.

When a class calls a method, the JVM Stack, PC Register, and local method stack are used.

Each line of code when a method is executed is executed line by line by the interpreter in the execution engine. Methods that are frequently called by hot spots in the method are optimized and executed by the JIT compiler. The GC will recycle unused objects in the heap. If you need to deal with the operating system, you need to use the local method interface.

2. Java runtime data area

During the execution of a Java program, the Java virtual machine divides the memory it manages into several different data areas. JDK 1.8 is slightly different from previous versions.

JDK 1.7

JDK 1.8

Thread private:

  • program counter
  • Virtual machine stack
  • native method stack

Thread shared:

  • heap
  • method area
  • Direct memory (not part of the runtime data area)

2.1 Program counter (PC register)

The program counter is a small memory space that can be viewed as a line number indicator of the bytecode executed by the current thread . Saves the address (line number) of the bytecode instruction being executed by the current thread. After the current instruction is executed, the program counter will automatically increase by 1 or jump to the address of other instructions to point to the address of the next instruction to be executed. Branching, looping, jumping, exception handling, thread recovery and other functions all rely on this counter to complete.

In order to return to the correct execution position after thread switching , each thread needs an independent program counter . The counters between threads do not affect each other and are stored independently. We call this type of memory area "thread-private" memory.

So the program counter has two main functions:

  • The bytecode interpreter reads instructions sequentially by changing the program counter, thereby realizing code flow control , such as sequential execution, selection, looping, and exception handling.
  • In the case of multi-threading, the program counter is used to record the execution position of the current thread , so that when the thread is switched back, it can be known where the thread ran last time.

Notice

  • The program counter is the only  memory area where OutOfMemoryError (OOM) will not occur  . Its life cycle is created with the creation of the thread and dies with the end of the thread.
  • The PC register in the JVM is an abstract simulation of the physical PC register.

There is a place on the Internet where it is still controversial. Some say that the next instruction is stored, but I read the official Oracle document:
Chapter 2. The Structure of the Java Virtual Machine (oracle.com)

You can see that the official website means that "currently being executed" at that time is the instruction currently being executed.

Analyze the specific steps:

  1. Program Counter Initialization: Before the program starts running, the program counter is initialized to point to the address of the first instruction to be executed. For example, it is 10000 now;
  2. Instruction execution: The CPU retrieves the instruction corresponding to the instruction address stored in the program counter from the memory and executes the instruction. After the current instruction is executed, the program counter will automatically increase by 1 or jump to the address of other instructions to point to the address of the next instruction to be executed. For example, it is 10001 now;
  3. Instruction jump: When the program needs to perform operations such as branching, looping, or function calls, the program counter will be updated to the new instruction address so that the CPU can jump to the new location to continue executing the program. This jump can be conditional or unconditional, and can be implemented in various ways, such as conditional statements, loop statements, function calls, etc.
  4. Interrupt processing: When the computer encounters a hardware failure, system error or other interrupt event, the program counter may also be updated to the entry address of the interrupt service routine so that the CPU can immediately jump to the interrupt handler to perform the corresponding operation.

In fact, I think we can see from the steps why there are differences. During the fetching and execution process, it is still the address of the current instruction. What is stored between the completion of execution and the next fetch is the address of the next instruction . So both statements make sense.

Features

  • Is thread private
  • There will be no memory overflow

2.2Java Virtual Machine Stacks

The Java virtual machine stack describes the memory model of Java method execution. The Java virtual machine uses methods as the most basic execution unit . The "Stack Frame" is the data structure behind the virtual machine's method invocation and method execution . It is also the virtual machine's virtual machine runtime data area. Stack elements of Virtual Machine Stacks .

  • Each stack is composed of multiple stack frames (Frame) , corresponding to the memory occupied each time a method is called , and is used to store information such as local variable tables, operand stacks, dynamic links, method exits, etc.
  • The process from the beginning of the call to the end of execution of each method corresponds to the process of a stack frame from being pushed into the stack to being popped out of the stack in the virtual machine stack.
  • In an active thread , only the stack frame at the top of the stack is valid and is called the current stack frame . The method associated with this stack frame is called the current method . All bytecode instructions run by the execution engine only operate on the current stack frame.
  • If other methods are called in this method, the corresponding new stack frame will be created and placed on the top of the stack to become the new current frame.

2.2.1 Composition of stack frame

Detailed explanation of operating command mnemonics:

Practical detailed explanation of java decompilation bytecode (operation instruction mnemonic)_Bytecode decompilation_Natural Player's Blog-CSDN Blog

Creating a new object is divided into 4 steps:

  1. new: Create a new object, allocate storage space for the object in the heap, and push it onto the top of the operand stack;
  2. dup: Copy the word-length content at the top of the stack and push it into the stack (at this time, the stack has two identical addresses);
  3. invkespecial: The constructor calls the initialization method, and the ByteCodeTest object reference (dup) pops up from the top of the operand stack;
  4. astore_1: Take the ByteCodeTest object from the top of the operand stack and store it in local variable 1.

There are 5 ways to call methods:

  1. invokespecial: Call the current class method;
  2. invokevirtual: Call the method of the introduced class;
  3. invokeinterface: Call interface method;
  4. invokestatic: call a static method;
  5. invokedynamic: Call a method resolved at runtime.

local variable table

Defined as a numeric array, it is mainly used to store method parameters and local variables defined in the method body . These data types include various basic data types, object references (references), and returnAddress types.

The capacity of the local variable table is based on the variable slot as the smallest unit. Each variable slot can store 32-bit memory space. For example, boolean, byte, char, short, int, float, reference. For data types (long, double) with a length of 64 bits, the virtual machine allocates two consecutive Slot spaces in a high-bit alignment manner, which is equivalent to dividing a read and write of the long and double data types into two 32-bit reads and writes. .

If an instance method is executed (a method not modified by static), the variable slot indexed at position 0 in the local variable table is used by default to pass a reference to the object instance to which the method belongs. In the method, the keyword "this" can be used to pass the reference. Access this implicit parameter and occupy the variable slot at position 0.

The remaining parameters are arranged in the order of the parameter table, occupying the local variable slots starting from 1. After the parameter table is allocated, the remaining variable slots are allocated according to the variable order and scope defined within the method body.

Example:

    private static void test1() {
        String a = "a";
    }
    private  void test2() {
        String a = "a";
    }

test1 is a static method. View the bytecode file. astore_0 means placing the top element "a" on the stack at the position of index 0 in the local variable table.

test2 is an instance method. Check the bytecode file. astore_1 means to put the top element "a" on the stack into the local variable table index 1, then the position 0 is the implicit this.

Variable slot reuse

In order to save the memory space consumed by the stack frame as much as possible, the variable slots in the local variable table can be reused. The scope of the variables defined in the method body does not necessarily cover the entire method body. If the current bytecode PC counter The value has exceeded the scope of a certain variable, then the variable slot corresponding to this variable can be given to other variables for reuse.

private static void test1() {
    {
         String a = "a";
    }
    String b = "b";//此时变量a已经出了作用于,变量b会复用a的变量槽
}

In the comment part of the code, variable a is now out of scope, and variable b will reuse the variable slot of a.

operand stack

In addition to the local variable table, each independent stack frame also contains a last-in-first-out operand stack, which can also be called an expression stack. Operand stack. During method execution, data is written to or extracted from the stack according to bytecode instructions, that is, push and pop. The operand stack is mainly used to save the intermediate results of the calculation process and also serves as a temporary storage space for variables during the calculation process.

dynamic link

Mainly serves the scenario where one method needs to call other methods. The constant pool of the Class file stores a large number of symbol references, such as symbol references for method references. When a method wants to call other methods, it needs to convert the symbolic reference pointing to the method in the constant pool into a direct reference in the memory address. The function of dynamic linking is to convert symbol references into direct references to calling methods . This process is also called dynamic linking .

Concept supplement: symbolic quotation, direct quotation, refer to the following articles

A brief analysis of symbol references and direct references in JVM_Symbol references and direct references_This Guabaoshuomo's Blog-CSDN Blog

2.2.2 Problem analysis

Will a lot of stack frames be created when one method calls another method?

will be created. If there is a dynamic link in a stack that calls other methods, a new stack frame will be created. The stack is in order. If one stack frame calls another stack frame, the other stack frame will be queued above the caller.

Does garbage collection involve stack memory?

Won't. Stack memory is generated by method calls, and the stack will be popped after the method call is completed.

Is larger stack memory allocation better?

no. Because the physical memory is fixed, the larger the stack memory, the more recursive calls can be supported, but the fewer executable threads will be.

Are local variables within methods thread-safe?

Not necessarily. If a mutable object passed in from the outside is used in the method, or the method returns a mutable object, then there may be thread unsafe issues. Because the state of mutable objects can be modified by multiple threads at the same time, using these mutable objects in a multi-threaded environment may cause thread safety issues.

2.2.3 Escape analysis

The basic principle of escape analysis is : analyze the dynamic scope of the object. When an object is defined in a method, it may be referenced by an external method, such as being passed to other methods as a calling parameter. This is called method escape ; even It may be accessed by an external thread, such as assigning a value to an instance variable that can be accessed in other threads. This is called thread escape ;

From never escaping, method escaping to thread escaping, it is called the different escape degrees of objects from low to high. If it can be proven that an object will not escape from a method or thread (in other words, other methods or threads cannot access the object through any means), or the degree of escape is relatively low (only the method escapes but not the thread) ), different levels of optimization may be adopted for this object instance.

①Allocation on stack

Stack Allocations: In the Java virtual machine, allocating memory space for created objects on the Java heap is almost common sense to Java programmers . Objects in the Java heap are shared and visible to each thread, as long as they persist. With a reference to this object, you can access the object data stored in the heap. The garbage collection subsystem of the virtual machine will recycle objects that are no longer used in the heap, but the recycling action, whether it is marking and filtering out recyclable objects, or recycling and organizing memory, requires a lot of resources.

If you are sure that an object will not escape from the thread, it would be a very good idea to allocate memory for this object on the stack. The memory space occupied by the object can be destroyed when the stack frame is popped.

In general applications, the proportion of local objects that cannot escape at all and objects that cannot escape the thread is very large. If allocation on the stack can be used, a large number of objects will be automatically destroyed as the method ends. , the pressure on the garbage collection subsystem will be reduced a lot. Allocation on the stack can support method escape, but not thread escape.

code example

private  void test2() {
        String a = "a";
}

We created object "a", but the object cannot be accessed by external methods or other threads. At this time, the object is allocated on the stack and automatically destroyed when the method exits .

②Scalar analysis

Scalar Replacement : If a data can no longer be decomposed into smaller data to represent, the original data types in the Java virtual machine (int, long and other numerical types and reference types, etc.) cannot . Then these numbers can be called scalars . In contrast, if a piece of data can continue to be decomposed , it is called an aggregate . Objects in Java are typical aggregates .

If a Java object is dismantled and the member variables used are restored to their original types for access according to program access conditions, this process is called scalar replacement.

If escape analysis can prove that an object will not be accessed externally by the method, and that the object can be dismantled, then the program may not create the object when it is actually executed, but instead directly create several of its members used by this method. variables instead. After the object is split, in addition to allowing the object's member variables to be allocated, read and written on the stack (the data stored on the stack will most likely be allocated by the virtual machine to the high-speed register of the physical machine for storage), it can also be used for subsequent Further optimization means creating conditions.

Scalar replacement can be regarded as a special case of allocation on the stack. It is simpler to implement (there is no need to consider the allocation of the complete structure of the entire object), but it has higher requirements for the degree of escape. It does not allow the object to escape from the scope of the method.

code example

public int test(int x) { 
	int xx = x + 2;
	Point p = new Point(xx, 42); 
	return p.getX();
}

The code of the Point class is a POJO type containing x and y coordinates.
After escape analysis, it is found that the Point object instance will not escape to any extent within the scope of the entire test() method. In this way, it can be optimized with scalar replacement. Directly replace the internal x and y and decompose them into local variables within the test() method, thereby avoiding the actual creation of Point object instances. The optimized results are as follows:

public int test(int x) {
	 int xx = x + 2;
	 int px = xx; 
	 int py = 42 return px; 
}

Through data flow analysis, it is found that the value of py will not have any impact on the method, so you can safely eliminate invalid code and obtain the final optimization result.

public int test(int x) { return x + 2; }

③Synchronized elimination

Synchronization Elimination: Thread synchronization itself is a relatively time-consuming process. If escape analysis can determine that a variable will not escape the thread and cannot be accessed by other threads, then there will definitely be no competition in reading and writing this variable. The synchronization measures implemented on this variable can be safely eliminated

private void test2(){
        System.out.println(new StringBuffer("a").append("b"));
    }

The append method of this piece of code is locked, but through escape analysis it can be determined that the variable will not escape the thread and cannot be accessed by other threads. Although the append method is locked at this time, it will not be locked when the execution engine is executed. .

Research papers on escape analysis have been published as early as 1999, but it was not until JDK 6 that HotSpot began to support preliminary escape analysis, and until now this optimization technology is not mature enough and there is still a lot of room for improvement. The main reason for this immaturity is that the computational cost of escape analysis is very high, and there is no guarantee that the performance benefits brought by escape analysis will be higher than its consumption. If you want to determine with 100% accuracy whether an object will escape, you need to conduct a series of complex data flow-sensitive inter-process analyzes to determine the impact on this object
when each branch of the program is executed.

You can imagine that if after the escape analysis is completed, it is found that few objects that do not escape are found, then the time spent in the running period will be wasted. Therefore, the current virtual machine can only use less accurate, but relatively less time pressure. Small algorithm to complete the analysis .

For a long time, even the server-side compiler did not enable escape analysis by default. In some versions (such as JDK 6 Update 18), this optimization was completely disabled until JDK 7 . This optimization has become an option enabled by default in the server-side compiler . If necessary, or if it is confirmed to be beneficial to program operation, users can also use the parameter -XX:+DoEscapeAnalysis to manually enable escape analysis. After enabling it, the user can use the parameter -XX:+PrintEscapeAnalysis to view the analysis results. With escape analysis support, users can use the parameter -XX: +EliminateAllocations to enable scalar replacement, use +XX: +EliminateLocks to enable synchronization elimination, and use the parameter -XX: +PrintEliminateAllocations to view scalar replacement.

2.2.4 Memory overflow

Although the stack space is not unlimited, generally there will be no problem under normal calls. However, if the function call falls into an infinite loop, too many stack frames will be pushed into the stack and occupy too much space, causing the stack space to be too deep. Then when the depth of the thread request stack exceeds the maximum depth of the current Java virtual machine stack, a StackOverFlowError error is thrown.

Java methods have two return methods, one is to return normally through the return statement, and the other is to throw an exception. Regardless of the return method, the stack frame will be popped. In other words, the stack frame is created when the method is called and destroyed when the method ends. Regardless of whether the method completes normally or abnormally, it is counted as the end of the method .

In addition to the StackOverFlowError error, the stack may also cause an OutOfMemoryError error. This is because if the memory size of the stack can be dynamically expanded, and if the virtual machine cannot apply for enough memory space when dynamically expanding the stack, an OutOfMemoryError exception will be thrown. 

To briefly summarize, there are two kinds of errors that may occur in the stack when the program is running:

  • StackOverFlowError: If the memory size of the stack does not allow dynamic expansion, then when the thread request stack depth exceeds the maximum depth of the current Java virtual machine stack, a StackOverFlowError error will be thrown.
  • OutOfMemoryError: If the memory size of the stack can be dynamically expanded, and if the virtual machine cannot apply for enough memory space when dynamically expanding the stack, an OutOfMemoryError exception will be thrown.

-Xss can set the memory size of the stack

2.2.5 Thread running diagnosis

For example, a certain java program uses too much CPU

  1. Use the top command to check which process is occupying too much CPU.
    top
  2. Use the ps command to further check which thread is occupying too much CPU. eo is followed by the query content you are interested in, and grep filters to only see the target process related
    ps H -eo pid, tid(线程id), %cpu | grep 刚才通过 top 查到的进程号 
  3. Use the jstack command to generate a thread snapshot of the specified process in the virtual machine at the current moment, and a stack trace of the virtual machine. The thread snapshot is a collection of method stacks being executed by each thread of the specified process in the current virtual machine.
    jstack 进程id 

2.3Native Method Stacks

It is very similar to the role played by the virtual machine stack. The difference is: the virtual machine stack serves the virtual machine to execute Java methods (that is, bytecode), while the local method stack serves the Native methods used by the virtual machine. In the HotSpot virtual machine and the Java virtual machine stack are combined into one.

Native method (Native)

Since Java is a high-level language that is far away from the underlying hardware, sometimes it is impossible to operate the underlying resources. Therefore, Java adds the native keyword, and the methods modified by the native keyword can be rewritten in other languages. In this way, we can Write a native method and then rewrite it in C language to operate the underlying resources. Of course, using the native method will lead to low portability of the system, which needs to be noted.

Many methods in the Object class are native, that is, local methods

  • When a local method is executed, a stack frame is also created in the local method stack to store the local variable table, operand stack, dynamic link, and exit information of the local method.
  • After the method is executed, the corresponding stack frame will be popped out of the stack and the memory space will be released. Two errors, StackOverFlowError and OutOfMemoryError, will also occur.

2.4 piles

The largest piece of memory managed by the Java virtual machine. The Java heap is a memory area shared by all threads and is created when the virtual machine starts. The only purpose of this memory area is to store object instances. Almost all object instances and arrays allocate memory here. ​​​​​​

"Almost" all objects in the Java world are allocated on the heap. However, with the development of JIT compilers and escape analysis technology gradually maturing, allocation on the stack and scalar replacement optimization technology will lead to some subtle changes. All objects Allocating them to the heap gradually becomes less "absolute". Escape analysis has been enabled by default since JDK 1.7 . If the object reference in some methods is not returned or used outside (that is, it is not escaped), then the object can allocate memory directly on the stack.

The Java heap is the main area managed by the garbage collector, so it is also called the GC heap (Garbage Collected Heap) . From the perspective of garbage collection, since current collectors basically use generational garbage collection algorithms, the Java heap can also be subdivided into: new generation and old generation; more detailed ones include: Eden, Survivor, Old and other spaces. The purpose of further partitioning is to better reclaim memory, or to allocate memory faster.

Features

  • The heap is shared by threads. Objects in the heap need to consider thread safety issues
  • Has garbage collection mechanism

2.4.1 Evolution of the heap

Before JDK 7 and JDK 7, heap memory was usually divided into the following three parts:

  1. Young Generation memory
  2. Old Generation
  3. Permanent Generation

The Eden area and the two Survivor areas S0 and S1 shown in the figure below all belong to the new generation, the middle layer belongs to the old generation, and the bottom layer belongs to the permanent generation.

(There is a slight error in the picture below. The heap in JDK7 should include the permanent generation)

After JDK 8 version, PermGen (permanent generation) has been replaced by Metaspace (metaspace), which uses local memory.

In most cases, the object will first be allocated in the Eden area. After a new generation garbage collection, if the object is still alive, it will enter S0 or S1, and the age of the object will be increased by 1 (Eden area->Survivor area). The initial age becomes 1), and when its age increases to a certain level (default is 15 years old), it will be promoted to the old generation. The age threshold for objects to be promoted to the old generation can be set through the parameter -XX:MaxTenuringThreshold. 

"When Hotspot traverses all objects, it accumulates the size occupied by them in ascending order of age. When the accumulated age exceeds half of the survivor area, the smaller value of this age and MaxTenuringThreshold is used as the new The promotion age threshold”.

2.4.2 Contents of the heap

There are:

object instance

  • Object generated by class initialization
  • Arrays of basic data types are also object instances

String constant pool

The string constant pool  is an area specially opened by the JVM for strings (String class) in order to improve performance and reduce memory consumption. The main purpose is to avoid repeated creation of strings.

// 在堆中创建字符串对象”ab“
// 将字符串对象”ab“的引用保存在字符串常量池中
String aa = "ab";
// 直接返回字符串常量池中字符串对象”ab“的引用
String bb = "ab";
System.out.println(aa==bb);// true

The implementation of the string constant pool in the HotSpot virtual machine is src/hotspot/share/classfile/stringTable.cpp. StringTable can be simply understood as a fixed-size HashTable with a capacity of StringTableSize (can be set through the -XX:StringTableSize parameter). Save is the mapping relationship between string (key) and string object reference (value), and the string object reference points to the string object in the heap .

Before JDK1.7, the string constant pool was stored in the permanent generation. JDK1.7 The string constant pool and static variables moved from the permanent generation to the Java heap.

static variable

Static variables are variables with static modification. They are migrated from the method area to the heap in jdk7.

Thread Local Allocation Buffer

  • Thread private, but does not affect the commonality of the Java heap
  • The thread allocation buffer is added to improve the efficiency of object allocation.

2.4.3 Problem analysis

JDK 1.7 Why move string constant pool and static variables to the heap

Mainly because the GC recycling efficiency of the permanent generation (implemented in the method area) is too low, and GC will only be executed when the entire heap is collected (Full GC). There are usually a large number of created strings waiting to be recycled in Java programs. Putting the string constant pool in the heap can recycle string memory more efficiently and timely.

Does the string constant pool store string objects or references to string objects?

In JDK 6 and previous versions, the string constant pool saves string objects; in versions after JDK 6, both string objects and references to string objects are saved.

2.4.4 Memory overflow

The most common thing here is the OutOfMemoryError error, and there are several manifestations of this error, such as:

  1. java.lang.OutOfMemoryError: GC Overhead Limit Exceeded: This error occurs when the JVM spends too much time performing garbage collection and can only reclaim little heap space.
  2. java.lang.OutOfMemoryError: Java heap space: If when creating a new object, there is insufficient space in the heap memory to store the newly created object, this error will be raised. (It is related to the configured maximum heap memory and is subject to the physical memory size. The maximum heap memory can be configured through the -Xmx parameter. If there is no special configuration, the default value will be used)
  3.  ......

Specify heap memory size:

  • Minimum heap size: -Xms such as -Xms2m
  • The maximum size of the heap: -Xmx such as -Xmx8m

2.4.5 Heap memory diagnosis

  • jps tool: Check which java processes are in the current system
    jps
  • jmap tool: View memory usage of Java process
    jmap - heap 进程id
  • jconsole tool: graphical interface, multi-functional monitoring tool, capable of continuous monitoring
    jconsole

2.5 Method area

The "Java Virtual Machine Specification" clearly states: "Although all method areas are logically part of the heap, some simple implementations may not choose to perform garbage collection or compression." But for HotSpotJVM, methods The area also has an alias called Non-Heap (non-heap), the purpose is to separate it from the heap.

The "Java Virtual Machine Specification" only stipulates the concept of a method area and its role. How to implement the method area is something that the virtual machine itself has to consider. In other words, the implementation of the method area is different on different virtual machine implementations .

2.5.1 The relationship between method area, permanent generation and metaspace

The relationship between the method area, the permanent generation and the metaspace is very similar to the relationship between the interface and the class in Java. The class implements the interface, and the class here can be regarded as the permanent generation and metaspace, and the interface can be regarded as the method area, that is to say Permanent generation and metaspace are two ways to implement the method area in the HotSpot virtual machine's virtual machine specification. Moreover, the permanent generation is the method area implementation before JDK 1.8, and the method area implementation in JDK 1.8 and later becomes the meta space.

2.5.2 Why should we replace the permanent generation with metaspace?

"In-depth Understanding of the Java Virtual Machine" 3rd Edition 2.2.5:

The entire permanent generation has a fixed upper limit set by the JVM itself, which cannot be adjusted. The metaspace uses local memory and is limited by the available memory of the machine. Although the metaspace may still overflow, the probability of it occurring will be higher than before. Small.

When the metaspace overflows, you will get the following error: java.lang.OutOfMemoryError: MetaSpace

You can set the maximum metaspace size using the -XX:MaxMetaspaceSize flag, the default value is unlimited, which means it is only limited by system memory. -XX: MetaspaceSize resize flag defines the initial size of the metaspace. If this flag is not specified, Metaspace will dynamically resize based on application needs at runtime.

②The metaspace stores metadata of classes, so how many classes of metadata are loaded is not controlled by MaxPermSize, but by the actual available space of the system, so more classes can be loaded.

③In JDK8, when merging the codes of HotSpot and JRockit, JRockit has never had something called a permanent generation. After the merger, there is no need to set up such an additional permanent generation.

2.5.3 Contents of method area

The method area is used to store Class type information, constants, static variables, code cache compiled by the just-in-time compiler, etc. that have been loaded by the virtual machine. The heap mainly stores instantiated objects.

The method area is a memory shared by all threads. Before Java 8, it was placed in the JVM memory. It was implemented by the permanent generation. It was limited by the JVM memory size parameters. The contents of the permanent generation were removed in Java 8. The method area was composed of metaspace ( Meta Space) and put it directly into the local memory without being restricted by JVM parameters (of course, if the physical memory is full, the method area will also report OOM), and the string constant pool originally placed in the method area will be and static variables are transferred to the Java heap . The difference between the method area and other areas is that the content of the method area is slightly different during compilation and after class loading is completed, but in general it is divided into two parts:

①Class information (Klass)

Class metainformation is placed in the method area during class compilation, which contains the basic information of the class , including the class version, fields, methods, interfaces and constant pool table (Constant Pool Table)

Constant Pool Table

Compile the following code:

public class Test {
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

Then use the javap -v Test.class command to decompile and view the results.

Each instruction will correspond to an address in the constant pool table. The address in the constant pool table may correspond to a class name, method name, parameter type and other information.

The Constant Pool Table stores the literals and symbol references generated by the class during compilation. The virtual machine instructions find the class name, method name, parameter type, and literal information to be executed based on this constant table. This information is in After the class is loaded, it will be parsed into the runtime constant pool.

Concept supplement: literals

Java code cannot construct references during the compilation process. Literals are a representation of data during compilation:

int a=1;//这个1便是字面量
String b="iloveu";//iloveu便是字面量

②Runtime Constant Pool

  • The constant pool is in the *.class file. When the class is loaded, its constant pool information will be put into the runtime constant pool, and the symbolic addresses inside will be changed into real addresses.
  • The runtime constant pool is dynamic and can add data. The most commonly used one is the intern() method of the String class.

The runtime constant pool, method area, and string constant pool are all logical concepts that do not change with the implementation of the virtual machine and are public and abstract. Metaspace and Heap are physical concepts related to a specific virtual machine implementation and are private and abstract. specific

2.5.4 Problem analysis

Where are member variables, local variables, and class variables stored in memory?

class variable

  • Class variables are modified with the static modifier. Variables defined outside the method are generated and destroyed along with the Java process.
  • Before Java7, static variables were stored in the method area, and in Java7 they were stored in the heap.

Member variables

  • Member variables are variables defined in the class but not modified by the static modifier. They are part of the class instance as the instance of the class is created and destroyed.
  • Since it is part of the instance, when the class is initialized, the direct reference or value is taken from the runtime constant pool and put into the heap together with the initialized object.

local variables

  • Local variables are variables defined in methods of a class
  • When the method is called, it is put into the stack frame of the virtual machine stack. After the method execution is completed, it is popped out of the virtual machine stack, so it is stored in the virtual machine stack.

Where are constants modified by final stored?

The final keyword does not affect the location in memory. Please refer to the previous question for the specific location.

What is the relationship between class constant pool, runtime constant pool and string constant pool? What's the difference?

  • Both the class constant pool and the runtime constant pool are stored in the method area, and the string constant pool has been migrated from the method area to the Java heap in jdk7.
  • During the class compilation process, the class metainformation will be placed in the method area. Part of the class metainformation is the class constant pool, which mainly stores literals and symbol references, and part of the literals are text characters. When the class is loaded Resolve literal and symbolic references into direct references and store them in the runtime constant pool;
  • For text characters, they will search the string constant pool during parsing, find out the direct reference to the string object corresponding to the text character, and store the direct reference in the runtime constant pool; the string constant pool stores strings A reference to the object, not the string itself.

2.5.5 Characteristics of the method area

  • The Method Area, like the Java heap, is a memory area shared by each thread .
  • The method area is shared by threads. When multiple threads use a class, if the class has not been loaded, only one thread should load the class while other threads wait;
  • There is a garbage collection mechanism in the method area . Some classes become garbage when they are no longer used and require garbage cleaning.
  • The method area is created when the JVM is started, and its actual physical memory space can be discontinuous like the Java heap area.
  • The size of the method area, like the heap space, can be fixed or expandable.
  • The size of the method area determines how many classes the system can save. If the system defines too many classes, causing the method area to overflow, the virtual machine will also throw a memory overflow error : java.lang.OutOfMemoryError: PermGen space or java.lang. OutOfMemoryError: Metaspace. For example, the following three situations:
    • Load a large number of third-party jar packages;
    • Tomcat deploys too many projects (30~50);
    • A large number of dynamically generated reflection classes;

2.5.6 Set the size of the method area

The size of the method area does not have to be fixed, the JVM can dynamically adjust it according to the needs of the application.

jdk7 and before:

  • -XX:PermSize=N //Initial size of method area (permanent generation)
  • -XX:MaxPermSize=N //The maximum size of the method area (permanent generation), exceeding this value will throw an OutOfMemoryError exception: java.lang.OutOfMemoryError: PermGen

When the capacity of class information loaded by the JVM exceeds this value, an exception OutofMemoryError: PermGen space will be reported.

After JDK8:

Metaspace is used instead of the permanent generation, and the size of the metaspace can also be dynamically adjusted.

  • -XX:MetaspaceSize=N //Set the initial (and minimum size) of Metaspace
  • -XX:MaxMetaspaceSize=N //Set the maximum size of Metaspace

Because the metaspace uses local memory, the default size is platform-dependent.

Under Windows, -XX:MetaspaceSize is 21M, and the value of -XX:MaxMetaspaceSize is -1, which means there is no limit. In theory, it is the available memory size of the system.

Unlike the permanent generation, if you do not specify a size, the virtual machine will use up all available system memory by default. If the metaspace overflows, the virtual machine will also throw the exception OutOfMemoryError:Metaspace.

2.6 Let’s talk about the string constant pool (StringTable) again


 

Guess you like

Origin blog.csdn.net/qq_62767608/article/details/132816502