当前位置:网站首页>Fix the memory structure of JVM in one article

Fix the memory structure of JVM in one article

2022-07-05 22:53:00 Thousands of miles in all directions

Catalog

1. brief introduction

2. Program counter (PC register )

2.1 Function demonstration

2.2 About PC The interview questions

3. Virtual machine stack

3.1 First acquaintance with virtual machine stack

3.2 The internal structure of the stack frame

3.2.1 Local variable table

3.2.2 The stack of operands

3.2.3 Link introduction

3.2.4 Method return address

3.3 Common interview questions of stack

4. Local method interface and local method stack

4.1 Local method

4.2 Native Method Stack

5. Pile up

5.1 Preliminary study on heap

5.2 Heap memory allocation strategy

5.2.1 The idea of heap space generation

5.2.2 Illustrate the object allocation process

5.3 Stack space practice

5.3.1 Use JVisualVM View heap memory

5.3.2 adopt PrintGCDetails Command to view heap information

5.3.3 Set heap memory

5.3.4 adopt jsp+jstat Check the heap allocation of the process

5.3.5 Create a heap overflow problem

5.3.6 Common parameter settings of heap space

5.4 Introduction to code optimization

6. Method area

6.1 Stack 、 Pile up 、 Method area interaction

6.2 The internal structure of the method area

6.2.1 Type information

6.2.2 Domain (Field) Information

6.2.3 Method (Method) Information

6.2.4 non-final Class variables of type

6.2.5 Global constants :static final

6.2.6 Runtime constant pool

7. Direct memory


1. brief introduction

This chapter is JVM The framework and the most important content , The main problem to be solved is what is in the object we create , stay JVM How to store and use in . For example, when we write such a line of code :

Person person=new Person();

How to create this line of code step by step 、 What about storage and execution ? Previously, we introduced the basic process of class loading : load --> verification --> Get ready --> analysis --> initialization , After these stages are completed , Objects will be placed in memory , Wait for the execution engine to use . Memory is a very important system resource , It's hard disk and CPU Middle warehouse and Bridge , It carries the real-time operation of the operating system and application program .JVM The memory layout defines Java Memory request during run 、 Distribute 、 Managed policies , To ensure the JVM Efficient and stable operation of . Different JVM There are differences in memory division and management mechanism . The executive engine can be understood as the engine of the car , It needs to input oil 、 air 、 Coolant , Exhaust gas , And output power , But the input and output of the execution engine are all in memory .

This chapter combines JVM Virtual machine specification , Let's talk about the classic JVM Memory structure .Java Virtual machine is executing Java In the process of the program, the memory it manages will be divided into several different data areas . These areas have their own uses , And when it was created and destroyed , Some regions exist with the start of virtual machine process , Some areas are created and destroyed depending on the start and end of the user thread . according to 《Java Virtual machine specification 》 The provisions of the ,Java The memory managed by the virtual machine will include the following runtime data areas . Of course, different virtual opportunities are slightly different , The picture below is hotspot Memory structure :

We will expand on the specific details later , What we need to pay attention to now is , although Java Virtual machine defines several areas that will be used during program operation , But some of them will be created as the virtual machine starts , Destroy as virtual machine exits . Others correspond to threads one by one , These data regions corresponding to the thread are created and destroyed as the thread starts and ends . The white ones are private to individual threads , The red ones are shared by multiple threads , namely :

  • Each thread is unique : Independent program counters 、 Stack 、 Native Method Stack .

  • Sharing between threads : Pile up 、 Out of heap memory ( Permanent generation or meta space 、 Code cache ), It can be understood that a virtual machine has a group of such structures .

Heap area and method area are shared by all threads , Therefore, with the execution of the program, certain garbage content will be generated , This junk information 90% The above is in the heap , Therefore, more complex garbage collection strategies are needed , This is also the focus of our later research . And some other areas will also produce a small amount of garbage , Its garbage collection strategy is also relatively simple .

Next, let's take a detailed look at the functions of each structure 、 structure 、 Working process and other important issues .

2. Program counter (PC register )

JVM Program count register in (Program Counter Register) in ,Register The name of comes from CPU The register of , Registers store field information about instructions .CPU Only loading data into registers can run . But this is not a physical register in a broad sense , stay JVM It's just right PC A simulation of register , Counter used to process instructions related to the current thread .

It's a little bit with CPU The registers are similar , It takes up less space , But it runs fastest . The bytecode interpreter works by changing the value of this counter to select the next bytecode instruction to execute , So it's Program control flow It's a good indicator , Branch 、 loop 、 Jump 、 exception handling 、 Basic functions such as thread recovery rely on this counter .

stay JVM Specification , Each thread has its own program counter , And it's private , The life cycle is also consistent with the life cycle of threads . There is only one method in a thread at any time , It's called The current method . The program counter stores what the current thread is executing Java Methodical JVM Instruction address .

It should be noted that PC District is the only one without OutofMemoryError Area of situation . There is no garbage collection in local stack and other structures , But it may overflow .

2.1 Function demonstration

public class PCRegisterTest {
    public static void main(String[] args) {
        int i = 10;
        int j = 20;
        int k = i + j;
    }
}

After the compilation , perform javap -v PCRegisterTest.class, Check bytecode , with PC It's about :

 public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=4, args_size=1
         0: bipush        10
         2: istore_1
         3: bipush        20
         5: istore_2
         6: iload_1
         7: iload_2
         8: iadd
         9: istore_3
        10: return

The vertical row above 0 To 10, It can be understood as PC Counter , And on the right istore_1 Wait is the operation instruction , Here's the picture .

  If PC The serial number of the instruction issued is 5, Then the storage operation will be performed here , Then the local variable table will be operated , Operand stack, etc , Finally, it has to be converted into machine instructions to CPU To execute .

If we add code , You'll find the above Code Orders will continue to increase , The corresponding is to process each statement into an executable execution .

2.2 About PC The interview questions

problem 1: Use PC What's the use of register to store bytecode instruction address ?

This is because CPU You need to switch threads all the time , Now, after switching back , You need to know where to start and continue . To be specific JVM The bytecode interpreter needs to be changed PC Register to determine what kind of bytecode instruction should be executed next .

2.PC Why is the register set to private ?

The so-called multithreading will only execute the methods of one thread in a specific period of time ,CPU I'll keep switching tasks , This inevitably leads to frequent interruptions or recoveries , In order to accurately record the current bytecode instruction address that each thread is executing , The best way, of course, is to assign one to each thread PC register , In this way, each thread can be independently calculated , So that there will be no mutual interference .

3. Virtual machine stack

3.1 First acquaintance with virtual machine stack

Virtual machine stack is mainly used to manage method calls . When we write a method , for example :

public void function(){
   int a=0;
   function1(a);
}

We often say that when a method wants to execute a method call , For example, the above implementation function1(a) I will be the first to go function() The information of is saved to the stack , We'll continue after we've finished function(), that JVM How to save it specifically ? It is saved in stack frames , Every time a method call is executed, a stack frame is created .

Virtual machine stacks are created synchronously when threads are created , Threads are private , The lifecycle is also consistent with threads , The main function is to manage Java Operation of , Include local variables that hold methods 、 Part of the result , And participate in the call and return of methods . The stack frames are saved inside , Corresponding to each method call made by the thread , Therefore, stack frame can be understood as the operation unit of method call .

Stack is a fast and effective way to allocate storage , Access speed is second only to the program counter , however JVM Yes Java There are only two operations on the stack : Stack when executing method , Stack after completing the method . For a thread , At the same time , Only one stack frame is active , That is, only the stack frame corresponding to the currently executing method is valid . This frame also becomes the current frame (current Frame), Corresponding to the current stack frame is the current method (Current Method), The class that defines this method is the current class (Current Class). All bytecode instructions run by the execution engine we will introduce later operate only on the current stack frame .

If another method is called in one method , At this point, a new stack frame will be created for the new method and placed on the top of the stack , Become the new current frame , The previous frame will save the information and wait for the current frame to execute before continuing .

  If the current method calls another method , When the method returns, the execution result will be returned together , Then the virtual opportunity discards the current stack frame , Make the subsequent frame in the stack become the new current stack frame . This process is consistent with the stack operation .

reflection What exceptions may appear in the stack

From the above analysis, we can see , Stack can automatically manage space , There is no garbage collection problem , That common "StackOverflowError" What's the matter ?

JVM The specification allows Java Stack size is dynamic or fixed , If it's a fixed size , So a thread Java The virtual machine capacity can be selected independently when the thread is created . If the stack capacity allocated by the thread request exceeds Java Maximum capacity allowed by virtual machine stack , Will throw StackOverflowError abnormal .

Surely there will be no memory overflow problem in that stack ? No, it isn't , If Java The virtual machine stack can be expanded dynamically , And cannot apply for enough memory when expanding , Or when creating a new thread, there is not enough memory to create the corresponding virtual machine stack , that Java The virtual machine will throw OutOfMemoryError abnormal .

For example, the following code will throw “StackOverflowError”:

public class StackOverFlowTest {
    public static void main(String[] args) {
        test();
    }
​
    public static void test() {
        test();
    }
}

3.2 The internal structure of the stack frame

The internal part of stack frame includes local variable table 、 The stack of operands 、 Structures such as dynamic links and method return addresses .

3.2.1 Local variable table

Local variable table (Local variables) Also called local variable table or local variable table , 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 reference (reference), as well as returnAddress type .

The local variable table is actually an array , If its length is length, Parameters are indexed 0 The location of Index0 Start storing , To length-1 End of position for . this length Units have a special name : Slot slot, Therefore, the number of slots is the length of the local variable table .

The local variable table stores various basic data types known at compile time (Integer、Char etc. 8 Large packaging ), Reference type (reference),returnAddress Variable of type . The size of the local variable table is determined by the compiler , And stored in the Code Attribute maximum local variables In data item , therefore , The local variometer size does not change during method run .

In the local variable table ,32 Types within bits occupy only one slot( Include returnAddress type ),64 Bit type (long and double) Take two slot. among byte、short、char and boolean Will first turn into int, Therefore, a slot will be occupied .

In order to improve access efficiency ,JVM For each in the local variable table slot Assign an index , Through this index, you can successfully access the local variable values in the local variable table , Instead of starting from scratch , Here's the picture :

The comparison between static variables and local variables After the parameter list is assigned , According to the order and scope of the variables defined in the method body .

We know that class variable table has two initialization opportunities , For the first time “ Preparation stage ”, Perform system initialization , Set a zero value on a class variable , The other was in “ initialization ” Stage , Give the programmer the initial value defined in the code .

Unlike class variable initialization , There is no system initialization process in the local variable table , This means that once a local variable is defined, it must be artificially initialized , Otherwise it won't work .

public void test(){
    int i;
    System. out. println(i);
}

Such code is wrong , Can't use without assignment .

in addition , Variables in the local variable table are also important root nodes of garbage collection , As long as the object is directly or briefly referenced in the local variable table, it will not be recycled .

3.2.2 The stack of operands

Each independent stack frame is outside the table containing local variables , It also contains a last in first out operand stack , It can also be called expression stack , Its function is simply to calculate expressions , For example, to calculate 8+5=13. The stack of operands is in the process of method execution , According to bytecode instruction , Write data to the stack or pop data . for example :

public class TestAddOperation {
    public static void main(String[] args) {
        byte i = 15;
        int j = 8;
        int k = i + j;
    }
}

After the compilation , adopt javap command , We can see the following bytecode execution information , Among them we can see bipush Etc , This is the operation expression stack .

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=4, args_size=1
         0: bipush        15
         2: istore_1
         3: bipush        8
         5: istore_2
         6: iload_1
         7: iload_2
         8: iadd
         9: istore_3
        10: return

The expression stack is mainly used to save the intermediate results of the calculation process , At the same time, it serves as the temporary storage space for variables in the calculation process . The stack of operands is JVM A workspace of the execution engine , When a method is first executed , A new stack frame will be created . If the method being called has a return value , Its return value will be pushed into the operand stack of the current stack frame , And update the PC The next bytecode instruction to be executed in the register .

  The data type of the elements in the operand stack must strictly match the sequence of bytecode instructions . This is verified during compiler recompilation , At the same time, in the class loading process, the data flow analysis phase of the class verification phase needs to be verified again .

We sometimes see that Java The interpretation engine of virtual machine is stack based execution engine , The stack refers to the operand stack .

3.2.3 Link introduction

stay JVM in , Converting symbols into direct references to calling methods is related to the binding mechanism of methods , There are mainly two ways of static link and dynamic link .

Static linking is when a bytecode file is loaded into JVM Internal time , If the target method being called is known in the compiler , And the operation period remains unchanged , In this case, the process of converting the symbolic reference of the calling method into a direct reference is called static linking .

Dynamic linking is if the method being called cannot be determined in the compiler , in other words , The symbolic reference of the calling method can only be converted into a direct reference at the runtime of the program , Because of the dynamic nature of this reference conversion process , Therefore, it is also called dynamic link .

Why are there these two ways ? Because in some scenarios, it is impossible to determine all methods . Let's also make an analogy . We know that cars have fuel tanks , If there is no oil, go and add , This is dynamic link . When the rocket is launched, all the fuel must be ready , This is static linking . We know that cars are smaller , It can take many years to refuel all the time , But thousands of tons of rockets can only carry a few tons of load , This is because most of the space is filled with oil and oxygen . In fact, the operation of static link is fast , But it's bulky , Dynamic links are just the opposite .

Corresponding to static links and dynamic links are early binding and late binding . Early rise binding , It is the target method being called. If it is known at compile time , And the operation period remains unchanged , You can bind this method to the type it belongs to , thus , Because it is clear which target method is called , Therefore, you can use static links to convert symbol references to direct references . Late binding , If the called method cannot be determined at compile time , You can only bind related methods according to the actual type during the program run time , This binding method is also called late binding .Java Language support encapsulation 、 Inheritance and polymorphism , This requires early binding and late binding .

3.2.4 Method return address

Method return address returnAddress To store the call to the method PC Register value , Normal execution completion or exceptions will lead to the end of a method , Whatever way you exit , After the method exits, it returns to the location where the method was called . When the method exits normally , Of the caller PC The value of the counter is used as the return address , That is, the address of the next instruction of the instruction calling the method . And by the exception of the exit , The return address is determined by the exception table , This information is generally not saved in the stack frame .

Essentially , Method exit is the process of the current stack frame out of the stack , In this case, we need to restore the local variable table of the upper method 、 The stack of operands 、 Push the return value into the operand stack of the caller stack frame 、 Set up PC register , Let the caller continue . If the throw is abnormal , It will not throw exceptions to the upper caller .

3.3 Common interview questions of stack

1. For example, stack overflow ?(Stack OverflowError)

adopt -Xss Set the stack size :OOM

2. Can adjusting the stack size ensure no overflow ? You can't

3. Is the larger the stack memory allocated, the better ? No !

4. Will garbage collection involve virtual machine stacks ? I won't !

5. Whether the local variables defined in the method are thread safe ? Specific case specific analysis

4. Local method interface and local method stack

4.1 Local method

In short , Local method (Native Method) It's just one. Java Call not Java Interface implemented by code , such as C Language, etc. . In fact, many languages have such characteristics , For example, in C++ Can be used in extern "C" inform C++ The compiler calls a C Function of . The original intention of the local interface is to integrate C/C++ Program , Later, it gradually evolved to be able to integrate different programming languages into Java used .

identifier native Can be compared with other java Identifiers are used together , however abstract With the exception of . Defining a native method when , Does not provide an implementer ( It's like defining a Java interface), Because its realization is caused by non java Language is realized on the outside , As long as the method is clearly marked , for example :

public class IHaveNatives {
    public native void Native1(int x);
    public native static long Native2();
    private native synchronized float Native3(Object o);
    native void Native4(int[] ary) throws Exception;
}

Why use Native Method Well ? although Java It is very convenient to use , However, some tasks use Java It's not easy to implement , Or when we care about the efficiency of the program , Here's the problem , Common scenes are :

1. Sometimes Java Applications need to be associated with Java External hardware environment interaction , This is the main reason for the existence of local methods .Java Need to work with some The underlying system , In some cases, such as the exchange of hardware or operating system information . Local methods are providing such a communication mechanism : It provides us with a very simple interface , And we don't have to understand Java Trivial details beyond the application .

2. Interaction with the operating system .Java Language needs to go through JVM Processing can be executed by the operating system ,JVM Supporting Java The language itself and the runtime library , It is Java The platform on which programs live . But anyway , It's not a complete system after all , Many still rely on the support of the operating system . By using local methods , We can use Java Realized jre Interaction with the underlying system , even to the extent that JVM Part of it is to use C Written .

For example, many such methods are used at the bottom of multithreaded code , for example Thread There is such a method at the bottom :

private native void start0();

however , At present, this method is used less and less , Except for hardware related applications , Such as through Java Program driven printer or Java System management production equipment , It is rare in enterprise applications . Because now the communication between heterogeneous fields is very developed , For example, network protocols can be used to communicate with each other without integration .

4.2 Native Method Stack

Java Virtual machine stack management Java Method call , The local method stack is used to manage calls to local methods . Native Method Stack , It's also thread private . Local methods generally use C Language or C++ The realization of language .

The local method stack can be implemented as a fixed or dynamically expandable memory size ( In terms of memory overflow, it is the same as the virtual machine stack ):

  • If the stack capacity allocated by thread request exceeds the maximum allowed capacity of local method stack ,Java The virtual machine will throw a stackoverflowError abnormal .

  • If the native method stack can be dynamically extended , And can't get enough memory when trying to expand , Or when creating a new thread, there is not enough memory to create the corresponding local method stack , that Java The virtual machine will throw a outofMemoryError abnormal .

When a thread calls a local method , It's entering a whole new world that's no longer limited by virtual machines . It has the same permissions as a virtual machine . Local methods can access the runtime data area inside the virtual machine through the local method interface , You can even use the registers in the local processor directly , You can also allocate any amount of memory directly from the heap of local memory .

however , Not all JVM Both support local methods . because Java The virtual machine specification does not explicitly require the language of the local method stack 、 How to realize it 、 Data structure, etc . If JVM The product is not intended to support native Method , You don't need to implement a local method stack . At present, it is most used Hotspot JVM in , Directly combines the local method stack with the virtual machine stack .

5. Pile up

5.1 Preliminary study on heap

Let's start with a question , What are heaps and stacks ? We often hear “ Stack ” The concept of , Are the two the same thing ? No, it isn't , A stack is a unit of runtime , And the heap is the unit of storage . The stack solves the running problem of the program , That is, how the program is executed , Or how to process data . Heap solves the problem of how to store and manage data .

For example, we define such a class :

class School{
  Student student;
  Teacher teacher;
}

We often say here student and teacher It's a reference to an object , In fact, if we use school object , There will be two addresses inside , These two addresses point to the actual storage in the heap student and teacher The address of .

In our application , Arrays and objects may never be stored on the stack , Because the stack frame holds references , This reference points to the location of the object or array in the heap . It also means that , At the end of the method , Objects in the heap will not be removed immediately , It's only removed when garbage is collected , Therefore, heap is also a key area for garbage collection .

Heap for a JVM The process is unique , It is shared by all threads , One JVM There is a runtime data area in the example , A runtime data area has only one heap and one method area . And this heap area is JVM It is created at startup , The size of the space is determined , The pile is JVM The largest memory space managed , And the size of heap memory can be adjusted .

《Java Virtual machine specification 》 Regulations , The heap can be in a physically discontinuous memory space , But logically it should be seen as continuous . It also stipulates that all object instances and arrays should be allocated on the heap at runtime .

public class SimpleHeap {
    private int id;// attribute 、 Member variables 
​
    public SimpleHeap(int id) {
        this.id = id;
    }
​
    public void show() {
        System.out.println("My ID is " + id);
    }
    public static void main(String[] args) {
        SimpleHeap sl = new SimpleHeap(1);
        SimpleHeap s2 = new SimpleHeap(2);
​
        int[] arr = new int[10];
        Object[] arr1 = new Object[10];
    }
}

Most modern garbage collectors are designed based on the theory of generational collection , The heap space is subdivided into :

  1. Java7 And before that, heap memory is logically divided into three parts : New Area + Retirement area + The permanent zone

    • Young Generation Space New Area Young/New

      • It's divided into Eden Area and Survivor District

    • Old generation space Retirement area Old/Tenure

    • Permanent Space The permanent zone Perm

  2. Java 8 And then the heap memory is logically divided into three parts : New Area + Retirement area + Meta space

    • Young Generation Space New Area , It's divided into Eden Area and Survivor District

    • Old generation space Retirement area

    • Meta Space Meta space Meta

occasionally , We will see very similar names , For example, the new area 、 The new generation and The young generation is a thing ; Retirement area 、 The elderly area and the elderly generation are the same thing ; The permanent zone And the eternal generation is the same thing .

  1. The internal structure of the reactor ,JDK1.8 From the permanent generation before Replace with Meta space

5.2 Heap memory allocation strategy

5.2.1 The idea of heap space generation

Java The heaps in are divided into many types , Also known as generation , Why generations , Why is it so complicated ? Can't work without generations ? In fact, it can be done regardless of generations , All the objects are in one place ,GC It's no use trying to find out what objects you're looking for , This will scan all areas of the heap , Therefore, the performance is not high . This is like putting everyone in a school regardless of grade and subject , All in one classroom , Imagine what this is .

After research , Different objects have different life sizes , The time of birth and death is different , So after a period of execution , The content space will become fragmented , for example windows The self-contained mechanical hard disk and the self-contained disk defragmentation will show the following problems .

  in addition , Although different objects have different cycles , however 70%-99% The object of is a temporary object , That is, many objects are living and dying , If there are generations , Put the newly created object somewhere , When GC When you store this piece first “ transient ” The area of the object is recycled , This will make a lot of space available . If you recycle more Cenozoic , Take back the old generation less , Performance will improve a lot .

5.2.2 Illustrate the object allocation process

Allocating memory for new objects is a very rigorous and complex task ,JVM Not only do designers need to think about how memory is allocated 、 Where to distribute, etc , And because the memory allocation algorithm is closely related to the memory recovery algorithm , So we need to think about GC Whether memory fragmentation will occur in the memory space after memory recovery .

The specific process can be seen in the following figure , among Survivor The area is more complex , Detailed discussion later :

The specific process is :

  1. new Put your object first Eden District , This area has a size limit .

  2. When Eden When the space is full , The program also needs to create objects ,JVM Your garbage collector will be on Eden Zone for garbage collection (MinorGC),Eden Objects in the area that are no longer referenced by other objects are to be cleaned up , But there are still some that are still in use , At this time, all the live objects will be moved to Survivor0 District , after Eden The area is completely empty , You can continue to store new objects .

  3. If Eden The area is full again , Then you need to perform garbage collection again , in the meantime Survivor0 Some objects in the district have also become garbage . That is to say Eden Area and Survivor0 There are garbage objects and living objects in each area . At this time, the surviving objects of both will be moved to Survivor1 District . Why move here to S1 District ? We'll explain later .

  4. above S1 After the area is put into the object, it becomes S0 District , And the original S0 The area will be completely erased , And become S1 District , Then the above steps will be repeated . Why is it like this? We will explain it in detail later .

  5. S0 Live objects will be in S0 and S1 When can I go to the nursing area after going back and forth ? You can set the number of times , The default is 15 Time . We can set the age limit for the freshmen to enter the pension area , Set up JVM Parameters :-XX:MaxTenuringThreshold=N Set it up . If an object is in s0 and s1 Move repeatedly between zones 15 Times have not been clear , Will be moved to the elderly area .

  6. In the old age area , Relatively leisurely . When the old age area is out of memory , Trigger again GC:Major GC, Clean up the memory in the elderly area . If the elderly area has implemented Major GC after , It is found that the object cannot be saved , It will produce OOM abnormal .

In the above steps , although Eden District 、Survivor Garbage collection is available in both urban and elderly areas , But specific implementation strategies 、 Efficiency and method are different , Let's take a closer look at the garbage collection chapter later .

Now let's begin to explain the above paragraph 2~4 Step ,Survivor How to recycle garbage in the district , And why you have to move repeatedly .

1、 The objects we create , Generally, priority is given to Eden District , When we Eden When the area is full , It will trigger GC operation , It's generally called YGC / Minor GC operation . For example, in the figure below Eden Is already full , Red is the garbage object we want to recycle , And green is the object that can still be used . At this point we are going to 1 and 5 Move to S0 District , And at this point 1 and 5 Are closely arranged , There is no gap , This avoids the fragmentation problem .

When moving elements , We also set an age counter for each object , Objects that still exist after a recycle , Add their age to 1. After completing this step, it is equivalent to Eden The area has been completely released , Can store new objects .

2. With JVM Execute new procedure ,Eden The area may be full again , At this time, it will trigger MinorGC operation , here GC It will put Eden and Survivor From A garbage collection of objects in , Put the living objects in Survivor To(S1) District , At the same time, let the survivors age + 1.

  When operating above , When the object is removed from S0 Move to S1 after ,S0 It is formatted , become S1, And in the picture above S1 Will become the next S0, in other words s0 Area and s1 The zones are shifting to each other , And I just changed my name , Areas with objects are S0 District .

3、 We continue with object generation and garbage collection , When Survivor The age of the subjects in the study reaches 15 When , It will trigger once Promotion Promotion operation , That is to promote the young generation to the old generation .

About recycling : Frequent collection of , It's rarely collected in the retirement area , Almost not in the permanent zone / Meta space collection .

Why set up two Survivor District

What may feel strange here is why there are two S District , Why move to another one when performing garbage collection , Instead of cleaning yourself up ? We can explain it through the example of gold rush , If you want to search for gold in the desert , If there is only one box , You can only clean the sand in one corner of the frame , Then put the separated gold . The second is to prepare two boxes , One is used to shovel sand , The gold found is put in another box , Which one do you think is more efficient ? Of course, the latter .

Set the two Survivor Another great advantage of the zone is that it solves fragmentation , The risk of fragmentation is enormous , serious influence Java The performance of the program . Heap space is occupied by scattered objects in discontinuous memory , The most direct result is that there is not enough continuous memory space in the heap , Next, if the program needs to allocate memory to an object with a large memory demand, it will become very difficult . It's like when we climb a mountain , Everything in the backpack is next to , Finally, it is possible to save a complete space for the camera . If you leave a little space between each piece of luggage , It's likely that you won't be able to install a camera in the end . And we usually put the big ones first when packing , Finally, put the small one into the gap , If you can't, pour out everything and put it again . This is to solve the problem of fragmentation , And set two Survivor Zone is to achieve this effect .

Here we first introduce the size relationship of several spaces , Generally speaking, the partition is : The new generation and the old generation each occupy 1/3 and 2/3 The heap space . And the Cenozoic from、to and Eden The proportion of the area in the Cenozoic era is generally 1:1:8, But this parameter can also be adjusted : Default -XX:NewRatio=2, The new generation occupies 1, The old generation occupies 2, The Cenozoic took over the whole pile 1/3. You can modify -XX:NewRatio=4, The new generation occupies 1, The old generation occupies 4, The Cenozoic took over the whole pile 1/5.

5.3 Stack space practice

java Many tools are provided to assist us in monitoring and setting up heap space , for example :

  1. JDK Command line

  2. Eclipse:Memory Analyzer Tool

  3. Jconsole

  4. Visual VM( Real-time monitoring , recommend )

  5. Jprofiler(IDEA plug-in unit )

  6. Java Flight Recorder( Real-time monitoring )

  7. GCViewer

  8. GCEasy

We will gradually learn and use in the following content , Next, we will learn how to use several common tools

5.3.1 Use JVisualVM View heap memory

Let's write an example to check the allocation of the heap , Run the following code

public class HeapDemo {
    public static void main(String[] args) {
        System.out.println("start...");
        try {
            TimeUnit.MINUTES.sleep(30);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
​
        System.out.println("end...");
    }
​
}

We found the installation java The catalog of ,windows The system is as follows , and mac The system is generally /usr/bin Next , We find jvisualvm Program , And open , As shown in the figure below .

1、 double-click jdk This file in the directory

In addition, you need to install it when opening GC Plug in for , The method is to choose tools -> plug-in unit -> install Visual GC plug-in unit , Restart after installation .

  Then we run the code above , You can see the following :

  So we can see the basic heap space information .

5.3.2 adopt PrintGCDetails Command to view heap information

Besides using jvisualvm View heap information , We can do it in idea Directly output relevant information in . The way is to turn on “ function / Debug configuration ”, Add parameters at the virtual machine option "-XX:+PrintGCDetails", Then save to exit , Rerun HeapDemo Program .

  At this time, the runtime console will have nothing , When we terminate it, we will output the following :

Heap
 PSYoungGen      total 76288K, used 9181K [0x000000076ab00000, 0x0000000770000000, 0x00000007c0000000)
  eden space 65536K, 14% used [0x000000076ab00000,0x000000076b3f75e8,0x000000076eb00000)
  from space 10752K, 0% used [0x000000076f580000,0x000000076f580000,0x0000000770000000)
  to   space 10752K, 0% used [0x000000076eb00000,0x000000076eb00000,0x000000076f580000)
 ParOldGen       total 175104K, used 0K [0x00000006c0000000, 0x00000006cab00000, 0x000000076ab00000)
  object space 175104K, 0% used [0x00000006c0000000,0x00000006c0000000,0x00000006cab00000)
 Metaspace       used 3836K, capacity 4568K, committed 4864K, reserved 1056768K
  class space    used 430K, capacity 460K, committed 512K, reserved 1048576K

This is the heap information used by the program from run to end .

5.3.3 Set heap memory

Java The heap is used to store Java Object instances , And the size of the heap is JVM It's set when it starts , We can go through the options "-Xms" and "-Xmx" To set it up .

  • -Xms Used to represent the starting memory of the heap , Equivalent to -XX:InitialHeapSize

  • -Xmx Is used to represent the maximum memory of the heap , Equivalent to -XX:MaxHeapSize

By default , The size of the initial memory and the maximum memory is the size of the physical computer memory /4 . Once the memory size in the heap exceeds “-Xmx" The maximum memory specified , It will be thrown out. OutofMemoryError abnormal .

We usually will -Xms and -Xmx Both parameters are configured with the same value , This is because it is assumed that the two are different , Small initial memory , The maximum memory is large . If the heap is out of memory during run time , Will perform capacity expansion , Expand to the maximum memory . If there's enough memory and more , It will also be continuously reduced and released . Frequent expansion and release cause unnecessary pressure , To avoid the GC After adjusting the heap memory to bring pressure to the server . If the two settings are the same, there will be less frequent expansion and reduction steps .

If we will HeapDemo The virtual machine parameters of are set as follows :"-Xms10m -Xmx10m -XX:+PrintGCDetails", At this time, the following error will appear when running , It means there is not enough space .

[GC (Allocation Failure) [PSYoungGen: 2048K->496K(2560K)] 2048K->648K(9728K), 0.0017097 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 

We can go through Runtime Provides a method to get the current memory size , The code is as follows :

public class HeapSpaceInitial {
    public static void main(String[] args) {
​
        // return Java The total amount of heap memory in the virtual machine 
        long initialMemory = Runtime.getRuntime().totalMemory() / 1024 / 1024;
        // return Java The maximum amount of heap memory the virtual machine is trying to use 
        long maxMemory = Runtime.getRuntime().maxMemory() / 1024 / 1024;
​
        System.out.println("-Xms : " + initialMemory + "M");
        System.out.println("-Xmx : " + maxMemory + "M");
​
        System.out.println(" The original memory size of the system is :" + initialMemory * 64.0 / 1024 + "G");
        System.out.println(" The system memory size is :" + maxMemory * 4.0 / 1024 + "G");
​
        try {
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Output results :

-Xms : 245M
-Xmx : 3641M
 The original memory size of the system is :15.3125G
 The system memory size is :14.22265625G

We can modify the virtual machine options "-Xms100m -Xmx100m -XX:+PrintGCDetails" Look again :

At this time, the output result is :

-Xms : 96M
-Xmx : 96M
 The system memory size is :6.0G
 The system memory size is :0.375G
Heap
 PSYoungGen      total 29696K, used 4613K [0x00000007bdf00000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 25600K, 18% used [0x00000007bdf00000,0x00000007be381548,0x00000007bf800000)
  from space 4096K, 0% used [0x00000007bfc00000,0x00000007bfc00000,0x00000007c0000000)
  to   space 4096K, 0% used [0x00000007bf800000,0x00000007bf800000,0x00000007bfc00000)
 ParOldGen       total 68608K, used 0K [0x00000007b9c00000, 0x00000007bdf00000, 0x00000007bdf00000)
  object space 68608K, 0% used [0x00000007b9c00000,0x00000007b9c00000,0x00000007bdf00000)
 Metaspace       used 3860K, capacity 4572K, committed 4864K, reserved 1056768K
  class space    used 429K, capacity 460K, committed 512K, reserved 1048576K
​
 Process ended , Exit code  130 (interrupted by signal 2: SIGINT)

Why is it less 4M Well ? According to the above Heap Printed results , You can see from space and to space The size of 4M, And only one will be used at the same time , The other one is empty , So effective space is 100M-4M=96M.

5.3.4 adopt jsp+jstat Check the heap allocation of the process

To check the allocation of the heap , In addition to the above two ways , You can also use jsp+jstat Combine commands to view .

jps: see java process 
jstat: Check the memory usage of a process 

First , Start the program HeapSpaceInitial after , We input... At the terminal jps command , You can see the currently executing process , For example, my computer can see :

  You can see HeapSpaceInitial The corresponding process number is 27005. Then use the command jstat -gc process id, You can see the usage of the heap :

  The units of the above figures are KB, The meaning of each model selection is :

SOC: S0 The total capacity of the zone is 
S1C: S1 The total capacity of the zone is 
S0U: S0 The amount used in the zone 
S1U: S1 The amount used in the zone 
EC:  The total capacity of Eden Park is 
EU:  The amount of Eden Park used 
OC:  The total capacity of the old age is 
OU:  The amount used in the old days 

5.3.5 Create a heap overflow problem

Next, we create a heap overflow problem through an example

public class OOMTest {
    public static void main(String[] args) {
        ArrayList<Picture> list = new ArrayList<>();
        while(true){
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            list.add(new Picture(new Random().nextInt(1024 * 1024)));
        }
    }
}
​
class Picture{
    private byte[] pixels;
​
    public Picture(int length) {
        this.pixels = new byte[length];
    }
}

After the above code is executed for a period of time, the following error message will be output :

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
  at ch3_JMM.topic3_Dump.Picture.<init>(OOMTest.java:27)
  at ch3_JMM.topic3_Dump.OOMTest.main(OOMTest.java:18)

We pass... Again jvisualvm Take a look at the heap memory change graph :

  You can see Old The content of location is increasing , When it is full, report the above “Java heap space” abnormal .

If you turn on the sampler , And select “ Memory ”, You can see byte[] Occupied 99.9% Space , This is why we created too many large objects, resulting in heap memory overflow .

5.3.6 Common parameter settings of heap space

Official documents :https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html. Some commonly used ones are as follows :

//  The details of the parameters will be shown in JVM The next part : Performance monitoring and tuning , Let's get familiar with 
-XX:+PrintFlagsInitial  // View the default initial values of all parameters 
-XX:+PrintFlagsFinal  // See the final values of all the parameters ( There may be modifications , It's no longer the initial value )
-Xms  // Initial heap space memory ( Default to physical memory 1/64)
-Xmx  // Maximum heap space memory ( Default to physical memory 1/4)
-Xmn  // Set the size of the new generation .( Initial value and maximum value )
-XX:NewRatio  // The proportion of the new generation and the old generation in the stack structure is configured 
-XX:SurvivorRatio  // Set up a new generation of Eden and S0/S1 The proportion of space 
-XX:MaxTenuringThreshold  // Set the maximum age for the new generation of garbage 
-XX:+PrintGCDetails // Output detailed GC Processing logs 
// Print gc Brief information :①-Xx:+PrintGC ② - verbose:gc
-XX:HandlePromotionFalilure:// Whether to set up space allocation guarantee 

Here are a few more explanations , In the event of a Minor GC Before , Virtual opportunity checks whether the largest available continuous space of the old generation is larger than the total space of all objects of the new generation .

  • If it is greater than , This time Minor GC Is safe

  • If it is less than , Then virtual opportunity view -XX:HandlePromotionFailure Set whether the guarantee fails .

    • If HandlePromotionFailure=true, Then we will continue to check Is the maximum available continuous space of the old age greater than the average size of the objects promoted to the old age .

      • If it is greater than , Try to have a Minor GC, But this time Minor GC There are still risks ;

      • If it is less than , One time Full GC.

    • If HandlePromotionFailure=false, One time Full GC.

  1. stay JDK6 Update 24 after ,HandlePromotionFailure The parameters no longer affect the space allocation guarantee policy of the virtual machine , Observe openJDK Source code changes in , Although the source code also defines HandlePromotionFailure Parameters , But it's no longer used in code .

  2. JDK6 Update 24 And then the rule became As long as the continuous space of the old age is larger than the total size of the new generation of objects or the average size of previous promotions Minor GC, Otherwise, it will be Full GC, namely HandlePromotionFailure=true

5.4 Introduction to code optimization

With JIT The development of compile time and Escape analysis technology Gradually mature , On the stack 、 Scalar substitution Optimization technology will lead to some subtle changes , All the objects assigned to the heap are becoming less “ absolute ” 了 .

stay Java In the virtual machine , Object is in Java Memory allocated in the heap , It's a common sense . however , There is a special case , That's it If you go through escape analysis (Escape Analysis) After the discovery , If an object has no way to escape , Then it may be optimized to be allocated on the stack . This eliminates the need to allocate memory on the heap , There's no need for garbage collection , This is also the most common off heap storage technology .

Besides , be based on OpenJDK bespoke TaoBao VM, Among them, innovative GCIH(GC invisible heap) Technical realization off-heap, Will have a longer life cycle Java Objects from heap Move to heap Outside , also GC Unable to manage GCIH Inside Java object , In order to reduce GC The recycling frequency and promotion of GC The purpose of recovery efficiency is .

Use escape analysis , Objects on the heap can be allocated to the stack . This can effectively reduce Java A cross function global data flow analysis algorithm for synchronous load and memory heap allocation pressure in the program . Through escape analysis ,Java Hotspot The compiler can analyze the usage scope of a new object's reference to determine whether to allocate the object to the heap .

The basic behavior of escape analysis is to analyze the dynamic scope of objects : When an object is defined in a method , Objects are used only within methods , They think there is no escape . When an object is defined in a method , It is referenced by external methods , It is thought that escape happened . For example, passing it as a call parameter to other places .

Escape analysis is an example

1、 There is no escape object , Can be assigned to the stack ( Wireless safety ) On , With the end of method execution , Stack space is removed ( There is no need to GC)

W  w=new W
public void my_method() {
    V v = new V();
    // use v
    // ....
    v = null;
}

2、 In the following code , StringBuffer Variable of type sb To be called createStringBuffer() Method where used , So escape happened , Can't allocate... On the stack

public static StringBuffer createStringBuffer(String s1, String s2) {
    StringBuffer sb = new StringBuffer();
    sb.append(s1);
    sb.append(s2);
    return sb;
}

If you want to StringBuffer sb No escape , It can be written like this . there sb.toString() It's like creating a new object ,sb Object only in createStringBuffer Method is used , So you can allocate on the stack .

public static String createStringBuffer(String s1, String s2) {
    StringBuffer sb = new StringBuffer();
    sb.append(s1);
    sb.append(s2);
    return sb.toString();
}

Local variables can be used in development , Don't use definitions outside of methods , This optimization is also known as ” On the stack “.

6. Method area

6.1 Stack 、 Pile up 、 Method area interaction

When we write the following code :


Person person=new Person();

here Person Is the bytecode we generated , That is to say .class file , here JVM How did you save it ?

The method area mainly stores Class, The heap mainly stores instantiated objects , What is stored in the stack is the address of the object in the heap , For the example above , The specific storage strategy is :

  1. Person Class .class The information is stored in the method area

  2. Really created person Objects stored in Java In the pile

  3. person Variables are stored in Java In the local variables table of the stack , It's a common reference Field . In fact, it's in the pile person Address of the object .

  4. stay person In the object , There is a pointer to... In the method area Person Type data , Indicates that the person The object is in the method area Person class new Coming out .

Heap and stack problems , We have already introduced , Next, we will introduce the relevant contents of the method area in detail .

First , Where is the method area ? It is slightly different for different virtual machines , about HotSpotJVM for , The method area also has an alias called Non-Heap( Non heap ), The purpose is to separate it from the pile . therefore , The method area can be regarded as a block independent of Java Heap memory space .

Method area (Method Area) And Java Pile up , Is an area of memory Shared by each thread . When multiple threads load a single class at the same time , Only one thread can load this class , Other threads can only wait for the thread to load , Then use the class directly , That is, the class can only be loaded once .

Methods in JVM Created at startup , And its actual physical memory space neutralizes Java The heap area can also be discontinuous . And the size of the method area , Like heap space , You can choose to be fixed size or scalable . The size of the method area determines how many classes the system can hold , If the system defines too many classes , Cause method area overflow , Virtual machines also throw out memory overflow errors :java.lang.OutofMemoryError:PermGen space perhaps java.lang.OutOfMemoryError:Metaspace. Common problems are as follows : Load a lot of third party jar package 、Tomcat Too many projects deployed (30~50 individual ) Or generate a large number of reflection classes dynamically .

The number of classes that need to be loaded to execute a program may be far more than we think , For example, the following simple class :

public class MethodAreaDemo {
    public static void main(String[] args) {
        System.out.println("start...");
        try {
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
​
        System.out.println("end...");
    }
}

Execution time , adopt jvisualvm Observe , You can find that it is loaded 1600 Multiple classes .

Method area and permanent generation 、 The relationship of meta space

stay JDK7 In the past, we used to call the method area permanent generation , about Hotspot Come on , Method area and permanent generation can be regarded as equivalent . here we are JDK8 The concept of permanent generation is completely abandoned , Switch to and JRockit、J9 Same Metaspace implemented in local memory (Metaspace) Instead of .

The essence of meta space is similar to permanent generation , All right. JVM Implementation of method area in specification . But the biggest difference between meta space and permanent generation is : The meta space is not in the memory set by the virtual machine , It's using local memory .

Forever 、 It's not just the name of meta space that has changed , The internal structure has also been adjusted . according to 《Java Virtual machine specification 》 The provisions of the , If the method area cannot meet the new memory allocation requirements , Will throw out OOM abnormal .

6.2 The internal structure of the method area

What is stored in the method area ? What about the internal structure ?《 In depth understanding of Java virtual machine 》 The method area in the book (Method Area) The storage content is described as follows : It is used to store... That has been loaded by the virtual machine Type information 、 Constant 、 Static variables 、 Real time compiler compiled code cache etc. .

6.2.1 Type information

For each type of load ( class class、 Interface interface、 enumeration enum、 annotation annotation),JVM The following types of information must be stored in the method area :

  1. The full valid name of this type ( full name = Package name . Class name )

  2. The fully valid name of the direct parent of this type ( about interface or java.lang.Object, None of them has a parent )

  3. This type of modifier (public,abstract,final Some subset of )

  4. This type of direct interface has a sequence table

6.2.2 Domain (Field) Information

That is what we often call member variables , Domain information is an official name

  1. JVM Information about all fields of the type and the order in which the fields are declared must be stored in the method area .

  2. Domain related information includes : Domain name , Domain type , Field modifiers such as public,private,protected,static,final,volatile,transient wait .

6.2.3 Method (Method) Information

JVM The following information must be kept for all methods , As with domain information, it includes the order of declaration :

  1. Method name

  2. Return type of method ( Include void Return type ),void stay Java The corresponding in is void.class

  3. Number and type of method parameters ( According to the order )

  4. Method modifier (public,private,protected,static,final,synchronized,native,abstract A subset of )

  5. Bytecode of method (bytecodes)、 The stack of operands 、 Local variable table and size (abstract and native Methods except )

  6. Anomaly table (abstract and native Methods except ), The exception table records the start of each exception handling 、 End position 、 The code deals with the offset address in the program counter 、 Constant pool index of the caught exception class

give an example

public class MethodStructTest extends Object implements Comparable<String>,Serializable {
    // attribute 
    public int num = 10;
    public String info = "info";
    private static String str = " internal structure ";
​
    public void test1(){
        int count = 20;
        System.out.println("count = " + count);
    }
    public static int test2(int cal){
        int result = 0;
        try {
            int value = 30;
            result = value / cal;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
​
    @Override
    public int compareTo(String o) {
        return 0;
    }
}

Then use the following command :

javap -v MethodStrucTest.class

At this point, you can see that a particularly long code is generated , Let's take a few important parts and have a look .

1. Type information

In the runtime method area , The class information records which loader loaded the class , At the same time, the class loader also records which classes it loads

public class ch3_JMM.topic3_Dump.MethodStructTest extends java.lang.Object implements java.lang.Comparable<java.lang.String>, java.io.Serializable

2. Domain information ( Member information )

We defined two member variables above num and info, The relevant information is :

   public int num;
    descriptor: I
    flags: ACC_PUBLIC
​
  public java.lang.String info;
    descriptor: Ljava/lang/String;
    flags: ACC_PUBLIC

there descriptor: I Indicates that the field type is Integer, and info The corresponding is java.lang Under the String type .

there flags: ACC_PUBLIC The representation type is public Of ,ACC_PRIVATE Said is private Of ,ACC_STATIC The representation is static

// Domain information 
  public int num;
    descriptor: I
    flags: ACC_PUBLIC
​
  private static java.lang.String str;
    descriptor: Ljava/lang/String;
    flags: ACC_PRIVATE, ACC_STATIC

3. Methods information

  1. descriptor: ()V Indicates that the return value type of the method is void

  2. flags: ACC_PUBLIC Indicates that the method permission modifier is public

  3. stack=3 Indicates that the operand stack depth is 3

  4. locals=2 Indicates that the number of local variables is 2 individual ( Strength methods include this)

  5. test1() Method has no parameters , But its args_size=1 , This is because will this As a parameter

public void test1();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=2, args_size=1
         0: bipush        20
         2: istore_1
         3: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
         6: new           #6                  // class java/lang/StringBuilder
         9: dup
        10: invokespecial #7                  // Method java/lang/StringBuilder."<init>":()V
        13: ldc           #8                  // String count =
        15: invokevirtual #9                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        18: iload_1
        19: invokevirtual #10                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
        22: invokevirtual #11                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
        25: invokevirtual #12                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        28: return
      LineNumberTable:
        line 13: 0
        line 14: 3
        line 15: 28
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      29     0  this   Lch3_JMM/topic3_Dump/MethodStructTest;
            3      26     1 count   I

6.2.4 non-final Class variables of type

  1. Static variables are associated with classes , Load as class loads , They become a logical part of class data .

  2. Class variables are shared by all instances of a class , Even if there is no class instance , You can also visit it

give an example

  1. As shown in the following code , Even if we put order Set to null, There is no null pointer exception

  2. This further shows that static The fields and methods of type load as the class loads , Does not belong to a specific class instance

public class MethodAreaTest {
    public static void main(String[] args) {
        Order order = null;
        order.hello();
        System.out.println(order.count);
    }
}
​
class Order {
    public static int count = 1;
    public static final int number = 2;
​
​
    public static void hello() {
        System.out.println("hello!");
    }
}

Output results :

hello!
1

6.2.5 Global constants :static final

  1. The global constant is to use static final To embellish

  2. Be declared final Class variables are treated differently , Each global constant is assigned at compile time .

Check the code above , This part of the bytecode instruction

class Order {
    public static int count = 1;
    public static final int number = 2;
    ...
}    

perform javap -v Order.class You can see the following information about the above two variables :

 public static int count;
    descriptor: I
    flags: ACC_PUBLIC, ACC_STATIC
​
  public static final int number;
    descriptor: I
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
    ConstantValue: int 2

You can find staitc and final Modified at the same time number The value of has been written dead in the bytecode file when compiling .

6.2.6 Runtime constant pool

Use on us javap see class There is always such a long paragraph of content in the document :

Constant pool:
   #1 = Methodref          #13.#31        // java/lang/Object."<init>":()V
   #2 = Fieldref           #32.#33        // java/lang/System.out:Ljava/io/PrintStream;
   #3 = String             #34            // start...
   ·····
   #55 = Utf8               (J)V
   #56 = Utf8               printStackTrace

This is the constant pool of bytecode , The process of loading it into memory is the runtime constant pool . Why do you need a constant pool ? One java Classes in the source file 、 Interface , After compiling, a bytecode file is generated . and Java The bytecode in needs data support , Usually this data is too large to be stored directly in bytecode , So you can save it to the constant pool . This bytecode contains the address to the constant pool , Link them together when linking dynamically , For example, the following code :

public class SimpleClass {
    public void sayHello() {
        System.out.println("hello");
    }
}

Although the above code only 194 byte , But it uses String、System、PrintStream And Object Isostructure . Another example is in our file 6 A place used "hello" This string , If you don't use a constant pool , It needs to be in 6 Write it all over the place , Cause bloated . We can "hello" The required structure information is recorded in the constant pool , And pass The way of quoting , To load the 、 Call the required structure . If there's a lot of code , The structure of references will be more , Here is the benefit of constant pool .

A constant pool can be seen as a table , There are many contents in the constant pool , For example, quantity value 、 A string value 、 Class reference 、 Field reference 、 Method references and so on , The virtual machine instruction finds the class name to execute according to this constant table 、 Method name 、 Parameter type 、 Literal quantity, etc .

And the runtime constant pool (Runtime Constant Pool) Is part of the method area .JVM For each loaded type ( Class or interface ) Both maintain a constant pool . Data items in the pool are like array items , It's accessed by index . The runtime constant pool contains many different constants , Including the literal values that have been defined at compile time , It also includes method or field references that can only be obtained after runtime parsing . This is no longer the symbolic address in the constant pool , Here's the real address .

7. Direct memory

netty4 The data transfer

We all know kafka、rpc Many scenarios that require high transmission efficiency will be based on netty To realize network credit , that netty Why is it fast ? One of them is the use of direct memory , Thus, direct memory is a very important component . But direct memory is not part of virtual machine memory , Neither 《Java Virtual machine specification 》 Memory area defined in , But in Java Out of the pile 、 Memory range directly applied to the system .

Direct memory comes from NIO, By storing... In the heap DirectByteBuffer operation Native Memory , Obviously, the speed of accessing direct memory will be better than Java Pile up . That is to say, the read-write performance is high , So for performance reasons , Direct memory may be considered for frequent reading and writing ,Java Of NIO Library allows Java Programs use direct memory , For data buffers , This is it. netty One of the reasons for being fast .

BIO Indirect cache , It used to be BIO The architecture of , When reading and writing local files , We need to switch from user mode to kernel mode , The whole process is as follows :

  You can see that this process requires multiple file copies , This greatly reduces the efficiency of processing , If a direct buffer is used ,NIO Direct operation of physical disks , It saves the intermediate process , Here is the following ;

  The key point here is that there is no need to copy the file itself to user space when operating data in user space , Instead, the kernel space is processed directly through memory mapping . Let's explain it through the example of TV , In the early days, there was no remote control for TV , If you want to change channels, you must get up and go to the TV to adjust , With the remote control, just poke a few buttons , And memory mapping plays the role of remote control .

Of course, direct memory still has some disadvantages , Because of the direct existence of Java Out of pile , So its size is not directly limited to -Xmx The maximum heap size specified , But the system memory is limited ,Java The sum of heap and direct memory is still limited by the maximum memory the operating system can give . Because it is not affected JVM Memory recovery management , Therefore, the distribution and recovery cost is also relatively high .

原网站

版权声明
本文为[Thousands of miles in all directions]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/186/202207052242445824.html