当前位置:网站首页>Understand the JVM memory structure in one article
Understand the JVM memory structure in one article
2022-07-19 02:55:00 【The sound of the waves is still loud】
1. Preface
Java Virtual machines are medium 、 The knowledge that senior developers must cultivate , There is a high learning threshold , Many people are reluctant to touch it . It may be that the learning cost is high, or it may not be practical , So just don't bother “ Take care of ” It is . In fact, this idea is wrong . Let's take the simplest example ,JVM Basically, every recruitment company will ask questions , Will they be so boring to ask these unrealistic questions ? Obviously not . from JVM The failure caused by , It is very common in both our development process and production environment . such as OutOfMemoryError(OOM) Memory overflow problem , You should have met Tomcat Too many items are loaded in the container OOM problem , Lead to Web The project can't start . This is it. JVM The failure caused by . In the end JVM Where did the memory overflow happen ? Why is there a memory overflow ? How to monitor ? The most important thing is how to solve the problem ? The technology that can solve problems is the most practical and best technology . But you're right JVM The memory structure of is not clear , Just want to solve JVM The failure caused by , It's unrealistic . Only the foundation is laid , about JVM Fault problems can “ Break open a way through bramble and Thistle ”. This article explains in detail through codes and diagrams JVM Memory area , I believe after reading this article , You will be right JVM Memory heap 、 Stack 、 There is a clear understanding of the method area .
2. Run time data area
Java Virtual machine is executing Java In the process of the program, the memory it manages will be divided into several different data areas . Each region has its own role .
analysis JVM Memory structure , Mainly analysis JVM Runtime data storage area .JVM The runtime data area of mainly includes : Pile up 、 Stack 、 Method area 、 Program counter etc. . and JVM The optimization problem of is mainly Data area shared by threads in : Pile up 、 Method area .

2.1 Program counter
Program counter (Program Counter Register) It's a small amount of memory , It can be seen as Current thread Of the bytecode executed Line number indicator , Point to the next instruction code to be executed , The execution engine reads the next instruction . More precisely , The execution of a thread , Is to change the value of the counter of the current thread through the bytecode interpreter , To get the next bytecode instruction to be executed , So as to ensure the correct execution of the thread .
To ensure that after thread switching ( Context switch ) Can be restored to the correct execution position , Each thread has a separate program counter , The counters of each thread do not affect each other , Independent storage . That is to say, the program counter is Thread private memory .
If the thread executes Java Method , This counter records the address of the virtual machine bytecode instruction being executed ; If the execution is Native Method , The counter value is Undefined.
The program counter will not overflow memory (OutOfMemoryError namely OOM) problem .
2.2 Stack
JVM The stack in includes Java Virtual machine stack And local method stack , Of the two difference Namely ,Java The virtual machine stack is JVM perform Java Method service , The local method stack is JVM Used Native Method service . The two functions are very similar , This paper mainly introduces Java Virtual machine stack , Hereinafter referred to as stack .
Native What is the method ?
JDK There are many ways to use Native Embellished .Native Method Not in Java Language implementation Of , It is implemented in the local language ( such as C or C++). Personal understanding Native The method is to interact directly with the operating system . For example, the code that informs the garbage collector to perform garbage collection System.gc(), Is the use of native Embellished .
public final class System {
public static void gc() {
Runtime.getRuntime().gc();
}
}
public class Runtime {
// Use native modification
public native void gc();What is stack? ?
Definition : Limit linear tables that can only be inserted and deleted in the header . namely Pressing stack ( Push ) He Tan stack ( Out of the stack ) All right. Top element of stack operational . So the stack is Last in, first out Of .
The stack is Thread private Of , His life cycle is the same as thread . Each thread will allocate a stack space , namely Each thread has its own stack space .

What is stored in the stack ?
Stack frame Is the element of the stack . Each method creates a stack frame at execution time . Stack frame stores Local variable table 、 The stack of operands 、 Dynamic connections and method exits Etc . The process of each method from calling to the end of running , It corresponds to the process of a stack frame from pressing the stack to exiting the stack .

2.2.1 Local variable table
In stack frame , By a The local variable table stores data . The local variable table stores Basic data type (boolean、byte、char、short、int、float、long、double) Of local variable ( Including the parameters )、 And references to objects (String、 Array 、 Object etc. ), But don't store the contents of the object . The memory space required for the local variable table is Allocation completed during compilation , The local variometer size does not change during method run .
The capacity of local variables is expressed in Variable slot (Variable Slot) Is the smallest unit , Maximum storage capacity per variable slot 32 Bit data type . about 64 Bit data type (long、double),JVM It will be allocated two consecutive variable slots to store . hereinafter referred to as Slot .
JVM Use the local variable table through index positioning , The index ranges from 0 Start to the largest... In the local variable table Slot Number . Common methods and static Method In the 0 The storage of two slots is different . Not static Methods the first 0 The reference of the object instance to which the slot storage method belongs .

Slot Reuse ?
In order to save stack frame space as much as possible , In the local variable table Slot It can be reused Of . Method , Its scope does not necessarily cover the entire method . When the method runs , If already Beyond the scope of a variable , That is, the variable fails , So this variable corresponds to Slot It can be used by other variables , It's called Slot Reuse . Understand variables through an example “ invalid ”.
public void test(boolean flag)
{
if(flag)
{
int a = 66;
}
int b = 55;
}When the virtual machine is running test Method , A stack frame will be created , And push it into the stack of the current thread . When running to int a = 66 when , Create a... In the local variable of the current stack frame Slot Storage variable a, When running to int b = 55 when , At this time, the variable has been exceeded a The scope of ( Variable a The scope of {} Contained code block ), here a Is failure , Variable a The amount of Slot You can give it to b To use , This is it. Slot Reuse .
There are advantages and disadvantages in everything .Slot Although multiplexing saves stack frame space , But there will be some extra side effect . such as ,Slot The reuse of will directly affect the garbage collection behavior of the system .
public class TestDemo {
public static void main(String[] args){
byte[] placeholder = new byte[64 * 1024 * 1024];
System.gc();
}
}The code above is very simple , First fill the memory 64M The data of , Then notify the virtual machine for garbage collection . In order to see the garbage collection process more clearly , We add “-verbose:gc”, The function of this parameter is Print GC Information .

Printed GC The information is as follows :

You can see that the virtual machine does not recycle this 64M Memory . Why is it not recycled ? It's easy to understand , When executed System.gc() When the method is used , Variable placeholder Still in scope , Virtual machines will not be recycled , It's still “ It works ” Of .
We make some modifications to the above code , Make it scoped “ invalid ”.
public class TestDemo {
public static void main(String[] args){
{
byte[] placeholder = new byte[64 * 1024 * 1024];
}
System.gc();
}
}When running to System.gc() When the method is used , Variable placeholder The scope of has expired . It has “ It's useless ” 了 , Virtual opportunity reclaims the memory it occupies ?
Running results :

It is found that the virtual machine is still not recycled placeholder Variables occupy 64M Memory . Why is what you think not what you see ? Before explaining , Let's make a little modification to the code . stay System.gc() Before method execution , Add a local variable .
public class TestDemo {
public static void main(String[] args){
{
byte[] placeholder = new byte[64 * 1024 * 1024];
}
int a = 0;
System.gc();
}
}stay System.gc() Before method , Join in int a = 0, Then execute the method , Check garbage collection .

Find out placeholder Variables occupy 64M Memory space has been reclaimed , If you don't understand the local variable table Slot Reuse , It is difficult to understand this phenomenon .
and placeholder The key to whether variables can be recycled It's about : In the local variable table Slot Is there anything else about placeholder References to objects .
In the first revision , Limit the placeholder Scope of action , but After that, there is no read-write operation on local variable table ,placeholder Variables occupy in the local variable table Slot Not reused by other variables , So as GC Roots Part of the local variable table remains associated with it . therefore placeholder Variables are not recycled .
After the second revision , Run to the int a = 0 when , Already exceeded placeholder Scope of variable , here placeholder Occupied in the local variable table Slot It can be used by other variables . Variables a Just reuse placeholder The amount of Slot, So far, in the local variable table Slot No more placeholder Of quoted , The virtual machine is recycled placeholder The amount of 64M Memory space .
2.2.2 The stack of operands
The stack of operands It's a Last in, first out Stack . Of the operand stack Elements can be arbitrary Java data type . When the method is first executed , The operand stack is Empty , During method execution , Through bytecode instruction, the operand stack is Stack press and stack out The operation of . Usually Arithmetic operation It is through the operand stack , Or it can be done through the operand stack when calling other methods Parameter passing . Operand stack can be understood as stack frame used for Calculation Temporary data storage area .
Understand the operand stack through a piece of code .
public class OperandStack{
public static int add(int a, int b){
int c = a + b;
return c;
}
public static void main(String[] args){
add(100, 98);
}
}Use javap Decompile OperandStack after , According to the virtual machine instruction set , The operation process of the operand stack is as follows :

add When the method is first executed , The operand stack is empty . When executed iload_0 when , The local variable 0 Pressing stack , namely 100 Into the stack of operands . And then execute iload_1, The local variable 1 Pressing stack , namely 98 Into the stack of operands . Then perform iadd, Pop up two variables (100 and 98 Out of the operand stack ), Yes 100 and 98 In sum , And then the result 198 Pressing stack . And then execute istore_2, Pop up results ( Out of the stack ).
Here's a picture , Compare execution 100+98 operation , Changes of local variable table and operand stack .

What exceptions may appear in the stack ?
StackOverflowError: Stack overflow error
If a thread needs to use the stack size when calculating > Configuration allows maximum stack size , that Java The virtual machine will throw StackOverflowError
OutOfMemoryError: Out of memory
When the stack is dynamically expanded, if it cannot be applied to enough memory , Will throw out OutOfMemoryError abnormal .
How to set stack parameters ?
Use -Xss Set stack size , Usually hundreds K That's enough. . Because the stack is Thread private Of , The more threads , The larger the stack space .
The stack determines the depth of function calls . This is why recursive calls are used with caution . When called recursively , Every time the method is called, a stack frame is created and pressed . After a certain number of calls , The required stack size has exceeded the maximum stack parameter configured for virtual machine operation , Will throw StackOverflowError abnormal .
2.3 Java Pile up
The pile is Java The largest storage area in the memory managed by the virtual machine . Heap memory is all Thread sharing . Mainly for storage and use new Keyword created objects . all Object instances and arrays All have to be allocated on the heap . The garbage collector is based on GC Algorithm , Collect on the heap The amount of memory occupied by the object ( It collects the space occupied by the object, not the object itself ).
Java The pile is divided into The younger generation (Young Generation) and Old age (Old Generation); The younger generation is divided into Eden (Eden) And the survival zone (Survivor District ); The survival zone is further divided into From Survivor Space and To Survivor Space .
Younger generation storage “ Freshmen ”, Our newly created objects are stored in the younger generation . When the memory is full , Will trigger Minor GC, Clean up the memory space of the younger generation .
Older generation storage Long lived objects and large objects . Objects stored in the younger generation , After many times GC Objects that still survive will be moved to the old age for storage . When the old space is full , Will trigger Full GC.
notes :Full GC It's cleaning up the entire heap space , Including the young and the old . If Full GC after , Objects still cannot be stored in the heap , Will throw OutOfMemoryError abnormal .

Java Common parameters for heap settings
| Parameters | describe |
|---|---|
| -Xms | Initial size of heap memory |
| -Xmx(MaxHeapSize) | Maximum allowable heap memory size , Generally not larger than physical memory 80% |
| -XX:NewSize(-Xns) | The initial memory size of the younger generation |
| -XX:MaxNewSize(-Xmn) | The maximum allowed memory size of the younger generation , It can also be abbreviated |
-XX:NewRatio | Ratio of new generation to old generation The value is 4 Express The new generation : Old age =1:4, That is to say, the young generation occupy a large number of 1/5 |
| -XX:SurvivorRatio=8 | Young generation Eden District and Survivor Capacity ratio value of the zone , The default is 8 Two Survivor :eden=2:8, That is, a Survivor The younger generation 1/10 |
-XX:+HeapDumpOnOutOfMemoryError | When memory overflows , Export heap information to file |
-XX:+HeapDumpPath | Pile up Dump route -Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/a.dump |
-XX:OnOutOfMemoryError | Happen when OOM When memory overflows , Execute a script -XX:OnOutOfMemoryError=D:/tools/jdk1.7_40/bin/printstack.bat %p %p That represents a thread id pid |
| -XX:MaxTenuringThreshold=7 | Indicates how many times you have moved in the surviving area without being garbage collected , Into the old age |
2.4 Method area (Method Area)
The method area is the same as Java The pile is the same as all Thread sharing The range of , Used to store Class information loaded by virtual machine 、 Constant 、 Static variables 、 Real time compiler compiled code . More specifically , Static variables + Constant + Class information ( edition 、 Method 、 Field etc. )+ The runtime constant pool exists in the method area . Constant pools are part of the method area .

notes :JDK1.8 Use Metaspace MetaSpace Alternative method area , The meta space is not JVM in , It's using local memory . Two parameters of meta space :
- MetaSpaceSize: Initialization meta space size , Control occurrence GC threshold
- MaxMetaspaceSize : Upper limit of limit element space size , Prevent exceptions from taking up too much physical memory
The constant pool stores various... Generated by the compiler Literal and symbolic references . Literally Java The meaning of constant in . For example, text string ,final Modified constants, etc . Method references include the fully qualified names of classes and interfaces , Method name and descriptor , Field names and descriptors .

What's the use of constant pools ?
advantage : Constant pool avoids the frequent creation and destruction of objects, which will affect the system performance , Realize the sharing of objects .
Take a chestnut : Integer Constant pool ( Buffer pool ), And string constant pool
Integer Constant pool :
We know == The basic data type compares values , The reference data type compares the memory address .
public void TestIntegerCache()
{
public static void main(String[] args)
{
Integer i1 = new Integer(66);
Integer i2 = new integer(66);
Integer i3 = 66;
Integer i4 = 66;
Integer i5 = 150;
Integer i6 = 150;
System.out.println(i1 == i2);//false
System.out.println(i3 == i4);//true
System.out.println(i5 == i6);//false
}
}
i1 and i2 Use new keyword , Every time new One object will be created on the heap at a time , therefore i1 == i2 by false.
i3 == i4 Why true Well ?Integer i3 = 66 There is actually a step Packing The operation of , the int Type 66 Packed into Integer, adopt Integer Of valueOf Method .
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}Integer Of valueOf It's easy , It determines whether the variable is IntegerCache The minimum value of (-128) And maximum (127) Between , If in , Returns the contents of the constant pool , otherwise new One Integer object .
and IntegerCache yes Integer The static inner class of , What it does is it takes [-128,127] Number between “ cache ” stay IntegerCache Class cache Array ,valueOf Method is to call the constant pool cache Array , But will be i3、i4 Variable reference points to constant pool , There is no real creation object . and new Integer(i) Create objects directly in the heap .
IntegerCache Class , Contains a constructor , Three static variables :low minimum value 、high Maximum 、 and Integer Array , There is also a static code block . The function of static code block is to IntegerCache Class loading time , Yes high Maximum and Integer Array initialization . That is to say, when IntegerCache Class loading time , Max min , and Integer The array is already initialized . This Integer The array actually contains -128 To 127 All values between .
IntegerCache Source code
private static class IntegerCache {
static final int low = -128;// minimum value
static final int high;// Maximum
static final Integer cache[];// Cache array
// Privatized construction method , Don't let others create it . The idea of singleton mode
private IntegerCache() {}
// Class loading time , Execute static code block . Role is to -128 To 127 The number between is buffered in cache[] Array
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];// initialization cache Array , Determine according to the maximum and minimum value
int j = low;
for(int k = 0; k < cache.length; k++)// Traversal puts data into cache Array
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
}and i5 == i6 by false, Because of 150 be not in Integer Between the maximum and minimum values of the constant pool 【-128,127】, thus new An object , So for false.
Look at another paragraph Unpacking Code for .
public static void main(String[] args){
Integer i1 = new Integer(4);
Integer i2 = new Integer(6);
Integer i3 = new Integer(10);
System.out.print(i3 == i1+i2);//true
}because i1 and i2 yes Integer object , Can't use + The operator of the . First i1 and i2 Conduct Automatic dismantling operation , Unpack into int Then carry out numerical addition .i3 It is also to compare the value with it after unpacking . therefore i3 == i1+i2 It's actually quite int Whether the type values are equal , So for true.
String Constant pool :
String By final Modified class , It can't be inherited . There are usually two ways to create objects .
//1、
String str = new String("abcd");
//2、
String str = "abcd";First use new Objects created , Store in a pile . Each call creates a new object .
The second method is to create a String Class object reference variables str, Then go to the string constant pool through symbolic reference to find whether there is “abcd”, without , Will “abcd” Stored in the string constant pool , And put the str Variable references point to “abcd”. If there is already... In the constant pool “abcd” 了 , Will not be created in the constant pool “abcd”, It's about putting str The reference points to a in the constant pool “abcd”.
about String class ,equals Method is used to compare whether the string contents are the same ; == Number is used to compare whether the memory addresses are the same , That is, whether it points to the same object . Verify the above theory through code .
public static void main(String[] args){
String str1 = "abcd";
String str2 = "abcd";
System.out.print(str1 == str2);//true
}First, store variable references on the stack str1, Then find out whether there is... In the constant pool through symbolic reference abcd, No, , Will abcd Store in constant pool , And then str1 Pointing to the constant pool abcd. When creating a str2 object , Go to the constant pool and find that there is already abcd 了 , will str2 The reference points directly to abcd . therefore str1 == str2, Point to Same memory address .
public static void main(String[] args){
String str1 = new String("abcd");
String str2 = new String("abcd");
System.out.print(str1 == str2);//false
}str1 and str2 Use new Create objects , Different objects are created on the heap . Two references point to two different objects in the heap , So for false.
About strings + No. 1 connection problem :
For string constants + Connection No , At compile time ,JVM It will be optimized to + The value after the connection of number . So in The value of its string constant is determined during compilation .
String a = "a1";
String b = "a" + 1;
System.out.println((a == b)); //result = true
String a = "atrue";
String b = "a" + "true";
System.out.println((a == b)); //result = true
String a = "a3.4";
String b = "a" + 3.4;
System.out.println((a == b)); //result = true About string references + No. 1 connection problem :
For strings quote Of + No. 1 connection problem , Because the string reference is in The compilation time cannot be determined Coming down , In the process of Dynamically allocate and create new address storage objects at runtime .
public static void main(String[] args){
String str1 = "a";
String str2 = "ab";
String str3 = str1 + "b";
System.out.print(str2 == str3);//false
}For the above code ,str3 be equal to str1 quote + String constant “b”, Cannot determine at compile time , Dynamically allocate and assign the new address after connection to str3, therefore str2 and str3 The referenced memory addresses are different , therefore str2 == str3 The result is false
adopt jad decompiler , Analyze what the above code does . The compilation instructions are as follows :

after jad After the decompiler decompiles the code , The code is as follows
public class TestDemo
{
public TestDemo()
{
}
public static void main(String args[])
{
String s = "a";
String s1 = "ab";
String s2 = (new StringBuilder()).append(s).append("b").toString();
System.out.print(s1 = s2);
}
}Find out new One. StringBuilder object , And then use append The method optimizes + The operator .new Create objects on the heap , and String s1=“ab” Is to create objects in the constant pool , The memory addresses pointed to by the two applications are different , therefore s1 == s2 The result is false.
notes : We already know the string reference + No. 1 connection problem , In fact, it is to create a StringBuilder object , To use its append Method to connect strings . This is also a problem we need to pay attention to in our development , Namely Try not to for Use in loop + To manipulate strings . Look at the following code :
public static void main(String[] args){
String s = null;
for(int i = 0; i < 100; i++){
s = s + "a";
}
}stay for Use in loop + Connection string , Every cycle , It will be new StringBuilder object ,append After that “ abandon ” With it . If we create outside the loop StringBuilder object , Then use... In the loop append Method to append a string , Can save n-1 Time to create and destroy objects . So connect the string in the loop , In general use StringBuilder perhaps StringBuffer, Instead of using + Operation No .
public static void main(String[] args){
StringBuilder s = new StringBuilder();
for(int i = 0; i < 100; i++){
s.append("a");
}
}Use final Decorated string
public static void main(String[] args){
final String str1 = "a";
String str2 = "ab";
String str3 = str1 + "b";
System.out.print(str2 == str3);//true
}final The variable decorated is a constant , Its value can be determined at compile time . therefore str1 + "b" Is equivalent to "a" + "b", So the result is true.
String Object's intern Method .
public static void main(String[] args){
String s = "ab";
String s1 = "a";
String s2 = "b";
String s3 = s1 + s2;
System.out.println(s3 == s);//false
System.out.println(s3.intern() == s);//true
}Through the previous study, we know that ,s1+s2 Actually on the pile new One. StringBuilder object , and s Create objects in the constant pool “ab”, therefore s3 == s by false. however s3 call intern Method , The return is s3 The content of (ab) The address value in the constant pool . therefore s3.intern() == s The result is true.
Reference resources 《 In depth understanding of Java virtual machine 》
I think this article will help you , Please don't be stingy with your praise !
边栏推荐
- HCIA's first static routing experiment
- DHCP服务
- Rsync remote synchronization (incremental backup)
- Rhce8 Learning Guide Chapter 4 getting help
- 纯虚函数
- HCIA_ Nat experiment
- MySQL日志管理和完全备份增量备份与恢复
- Shell script case branch statement, pick the max address of anonymous login FTP
- 使用Virtual IP+Keepalived配置高可用
- Net-Snmp 相关命令
猜你喜欢
随机推荐
RHCE学习指南 第5章 vim编辑器
Squid agent service deployment
【NoSQL】redis主从、哨兵、集群
Redis之简单动态字符串SDS
RHCE-ansible第二次作业
Usage instructions for MDK keil/arm printf
时间管理方法的反思与探讨
Conditional statement of shell script
Swagger -- the most popular API framework in the world
HCIA_ Rip experiment
shell脚本之循环语句与函数
【MySQL】数据查询操作(select语句)
Multi layer packet structure and TCP triple handshake
String Full Permutation Problem
[solution] the local Group Policy Editor (gpedit.msc) in Win 11 cannot be opened
Upgrade kubernetes 1.23.2 to 1.24.1
echo -e用法
Expect interaction free
Shell script case branch statement, pick the max address of anonymous login FTP
时间复杂度和空间复杂度分析技巧









