当前位置:网站首页>JVM tuning 6: GC log analysis and constant pool explanation

JVM tuning 6: GC log analysis and constant pool explanation

2022-06-11 05:03:00 Please close your eyes when it is dark

GC Log analysis and constant pool explanation

GC Log analysis

about java We can configure the application through some configuration gc Print out all the logs , Then analysis gc Log to get key indicators , analysis GC reason , tuning JVM Parameters . Print GC Log method , stay JVM Add parameters to parameters ,%t Represents time
java -jar -Xloggc:./gc-%t.log -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+PrintGCCause -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M xxx.jar
Some logs show
 Insert picture description here
The first line in the figure is red , Is the configuration parameter of the project . Not only is printing configured here GC journal , And related VM Memory parameters . The default here is to use Parallel Garbage collector
The second line in the red box is in this GC Occurs at a point in time GC And then it's about GC situation

  • about 1.804: This is from jvm Start the calculation to this time GC Time passed , There is also a specific occurrence time and date ahead .
  • Full GC(Metadata GC Threshold) This is a time full gc, In brackets is gc Why , PSYoungGen It's the younger generation GC,ParOldGen It's from the old days GC,Metaspace It's the of meta space GC
  • 672K->0K(144384K), These three numbers correspond to GC The size occupied by the younger generation ,GC Later, the younger generation occupied , And the size of the entire young generation
  • 11816K->9417K(23552K), These three numbers correspond to GC It used to occupy the size of the old age ,GC Later, the old age occupied , And the size of the whole old age
  • 12488K->9417K(167936K), These three numbers correspond to GC The size of the heap memory previously occupied ,GC After that, the heap memory is occupied , And the size of the entire heap memory .
  • 20502K->20516K(1069056K), These three numbers correspond to GC The size of the memory that used to occupy meta space ,GC After that, the meta space memory is occupied , And the size of the entire Metaspace memory .
  • 0.1008111 Is the point in time GC It takes time .

It can be found several times from the log fullgc It is caused by insufficient meta space , So we can turn up the meta space

java -jar -Xloggc:./gc-test-%t.log -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:+PrintGCDetails -XX:+PrintGCDateStamps  
-XX:+PrintGCTimeStamps -XX:+PrintGCCause -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M 
xxx.jar

about CMS and G1 The logs of the collector will be a little different , You can also try to print the corresponding gc Log analysis , You can find gc In the log gc The steps are similar to those we talked about before
CMS

-Xloggc:d:/gc-cms-%t.log -Xms50M -Xmx50M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:+PrintGCDetails -XX:+PrintGCDateStamps  
-XX:+PrintGCTimeStamps -XX:+PrintGCCause -XX:+UseGCLogFileRotation XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M 
-XX:+UseParNewGC -XX:+UseConcMarkSweepGC

G1

-Xloggc:d:/gc-g1-%t.log -Xms50M -Xmx50M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:+PrintGCDetails -XX:+PrintGCDateStamps  
 -XX:+PrintGCTimeStamps -XX:+PrintGCCause  -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -XX:+UseG1GC 

These parameters above , Can help us to view and analyze GC Garbage collection of . But if GC There are many logs , Thousands of lines . So we can use some functions to help us analyze , Here's a recommended one gceasy(https://gceasy.io), Can be uploaded gc file , Then he will use the visual interface to show GC situation . As shown in the figure below
 Insert picture description here
This piece will be based on gc Automatic log analysis , Put forward the optimization plan , It's just a charge
 Insert picture description here
This piece is based on Gc Memory information for log analysis
 Insert picture description here
This block represents gc Time for
 Insert picture description here
Pile up gc Before and after the curve
 Insert picture description here
Gc Why
 Insert picture description here
There are many other functions , Know for yourself .

Class Constant pool and runtime constant pool

Class Constant pool can be understood as Class Resource warehouse in file . Class The file contains only the version of the class 、 Field 、 Method 、 Interface and other description information , Another piece of information is the constant pool (constant pool table), Used to store various literal quantities generated during compilation (Literal) And symbol reference (Symbolic References).

Literal

Literal quantity refers to the letters 、 A string of numbers or numeric constants . Literal can only appear with right value , The so-called right value refers to the value on the right of the equal sign , Such as :int a=1 there a Is the left value ,1 Is the right value . In this case 1 It's literal .

int a = 1;
int b = 2;
int c = "abcdefg";
int d = "abcdefg";

Symbol reference

Symbolic reference is a concept in compilation principle , It's relative to direct reference . It mainly includes three kinds of constants :

  • Fully qualified names of classes and interfaces
  • Name and descriptor of the field
  • The name and descriptor of the method

above a,b That's the field name , It's a kind of symbolic reference , also Math Class constant pool Lcom/tuling/jvm/Math Is the fully qualified name of the class ,main and compute It's the method name ,() It's a kind of UTF8 Format descriptor , These are all symbolic references .
These constant pools are now static information , Only when the runtime is loaded into memory , These symbols have the corresponding memory address information , Once these constant pools are loaded into memory, they become Runtime constant pool , The corresponding symbol reference will be transformed into the direct reference of the code loaded into the memory area when the program is loaded or running , That's what we call dynamic links .
for example ,compute() This symbolic reference is converted to at run time compute() Method specific code address in memory , Mainly through the type pointer in the object header to convert the direct reference .

String constant pool

The design idea of string constant pool
String assignment , Like any other object assignment , It costs a lot of time and space , As the most basic data type , A lot of frequent string creation , Greatly affect the performance of the program .JVM To improve performance and reduce memory overhead , There are some optimizations when instantiating string constants :

  • Create a string constant pool for Strings , Similar to the cache
  • When creating a string constant , First, query whether the string constant pool exists
  • The string exists , Return reference instance , non-existent , Instantiate the string and put it in the pool

Three string operations (Jdk1.7 And above )

  • Assign strings directly
    String s = "test"; // s Point to references in the constant pool
    String objects created in this way , Only in the constant pool . Because there is "test" This literal quantity , Create objects s When ,JVM I'll go to the constant pool first equals(key) Method , Judge whether there are the same objects . If there is , Returns the reference of the object in the constant pool directly ; without , A new object is created in the constant pool , And back to the reference .
  • new String();
    String s1 = new String("test"); // s1 Point to an object reference in memory
    This method ensures that the object exists in both the string constant pool and the heap , Create without , Finally, the object reference in heap memory is returned . The steps are roughly as follows :
    Because there is "test" This literal quantity , So we will first check whether there is a string in the string constant pool "test". non-existent , First, create a string object in the string constant pool ; Then go to memory and create a string object "test";
    exist , Just go to the heap memory and create a string object "zhuge"; Last , Returns a reference in memory to .
  • intern Method
String s1 = new String("test");   
String s2 = s1.intern();
System.out.println(s1 == s2);  //false

String Medium intern The method is a native Methods , When calling intern When the method is used , If the pool already contains one equal to this String Object's string ( use equals(oject) Method determination ), Then return the string in the pool . otherwise , take intern The returned reference points to the current string s1(jdk1.6 The version needs to be s1 Copy to the string constant pool ).

String constant pool location

Jdk1.6 And before : There is a permanent generation , The runtime constant pool is in the permanent generation , Runtime constant pool contains string constant pool
Jdk1.7: There is a permanent generation , But gradually “ To the eternal generation ”, The string constant pool is separated from the runtime constant pool in the permanent generation into the heap
Jdk1.8 And after : There is no permanent generation , Runtime constant pool in meta space , The string constant pool is still in the heap

String constant pool design principle
The bottom layer of the string constant pool is hotspot Of C++ Realized , The bottom layer is similar to a HashTable, What you save is essentially a reference to a string object . Look at a common interview question , The following code creates how many String object ?

String s1 = new String("he") + new String("llo");
String s2 = s1.intern();
System.out.println(s1 == s2);
//  stay  JDK 1.6  Lower output yes  false, Created  6  Objects 
//  stay  JDK 1.7  And above version output is  true, Created  5  Objects 
//  Of course, we didn't consider GC, But these objects do exist or have existed 

Why does the output change ? Mainly, the string pool is separated from the permanent generation 、 The reason for moving to the heap , intern() The method has changed accordingly :

  1. stay JDK 1.6 in , call intern() First of all, we will look in the string pool equal() Equal string , If a string exists, it returns the reference of the string in the string pool ; If the string does not exist , The virtual opportunity recreates an instance on the permanent generation , take StringTable A table entry of points to the newly created instance .
     Insert picture description here
  2. stay JDK 1.7 ( And above ) in , Because the string pool is no longer permanent ,intern() Some changes have been made , More convenient use of objects in the heap . When a string exists, and JDK 1.6 equally , However, when the string does not exist, there is no need to recreate the instance , You can point directly to instances on the heap .
     Insert picture description here

String Some examples of constant pool problem

String s0="testlsx";
String s1="testlsx";
String s2="test" + "lsx";
System.out.println( s0==s1 ); //true
System.out.println( s0==s2 ); //true

analysis : Because of the s0 and s1 Medium ”testlsx” Are string constants , They are determined at compile time , therefore s0==s1 by true; and ”test” and ”lsx” It's also string constants , When a string is connected by multiple string constants , It must be a string constant itself , therefore s2 It is also optimized as a string constant at compile time "testlsx", therefore s2 It's also in the constant pool ” testlsx” A reference to . So we came to s0==s1==s2;

String s0="testlsx";
String s1=new String("testlsx");
String s2="test" + new String("lsx");
System.out.println( s0==s1 );
System.out.println( s0==s2 );
System.out.println( s1==s2 );

analysis : use new String() The string created is not a constant , It can't be determined at compile time , therefore new String() The created string is not put into the constant pool , They have their own address space .s0 Or in the constant pool "testlsx” References to ,s1 Because it can't be determined at compile time , So it's a new object created at run time ”testlsx” References to ,s2 Because there's the second half new String(”lsx”) So it can't be determined at compile time , So it's also a newly created object ”testlsx” References to ; Understand these also know why come to this result .

String a = "a1";
String b = "a" + 1;
System.out.println(a == b); // true 
  
String a = "atrue";
String b = "a" + "true";
System.out.println(a == b); // true 
  
String a = "a3.4";
String b = "a" + 3.4;
System.out.println(a == b); // true

analysis :JVM For string constants "+“ Connection No , Will be at compile time ,JVM The constant string of ”+“ The connection is optimized to the value after connection , take "a” + 1 Come on , After being optimized by the compiler, the class It's already a1. At compile time, the value of its string constant is determined , So the final result of the above program is true.

String a = "ab";
String bb = "b";
String b = "a" + bb;
System.out.println(a == b); // false

analysis :JVM For string references , Because of the "+“ Connecting , There are string references , The value of the reference cannot be determined at the compile time of the program , namely "a” + bb Can't be optimized by compiler , Only during the run time of the program can we dynamically allocate and assign the new address after connection to b. So the result of the above program is false.

String a = "ab";
final String bb = "b";
String b = "a" + bb;
System.out.println(a == b); // true

analysis : And examples 4 The only difference is bb String with final modification , about final Decorated variable , It is parsed as a local copy of the constant value at compile time and stored in its own constant pool or embedded in its byte stream . So at this time "a" + bb and "a" + "b" The effect is the same . So the result of the above procedure is true.

String a = "ab";
final String bb = getBB();
String b = "a" + bb;
System.out.println(a == b); // false
private static String getBB() {
      
    return "b";  
}

analysis :JVM For string references bb, Its value cannot be determined at compile time , Only after the method is called during the program run time , Add the return value of the method to "a" To dynamically connect and assign the address to b, So above The result of the program is false.

About String It's immutable
From the above example, we can know that :

String  s  =  "a" + "b" + "c";  // It is equivalent to String s = "abc";
String  a  =  "a";
String  b  =  "b";
String  c  =  "c";
String  s1  =   a  +  b  +  c;

s1 This is not the same , It can be seen that JVM Script discovery s1 Of "+" The operation will become the following operation

StringBuilder temp = new StringBuilder();
temp.append(a).append(b).append(c);
String s = temp.toString();

Finally, let's take another example :

// String constant pool :" Computer " and " technology "  Heap memory :str1 Referenced object " Computer technology " 
// There's another one in heap memory StringBuilder The object of , But will be gc Recycling ,StringBuilder Of toString Method Society new String(), This String Is the real object reference returned 
String str2 = new StringBuilder(" Computer ").append(" technology ").toString();   // There was no " Computer technology " Literal , So it's not generated in the constant pool " Computer technology " object 
System.out.println(str2 == str2.intern());  //true
//" Computer technology "  There is no in the pool , But in heap in , be intern when , Will return directly to the heap Citation in 

// String constant pool :"ja" and "va"  Heap memory :str1 Referenced object "java" 
// There's another one in heap memory StringBuilder The object of , But will be gc Recycling ,StringBuilder Of toString Method Society new String(), This String Is the real object reference returned 
String str1 = new StringBuilder("ja").append("va").toString();    // There was no "java" Literal , So it's not generated in the constant pool "java" object 
System.out.println(str1 == str1.intern());  //false
//java Is the key word , stay JVM The initialization related classes must have been put into the string constant pool for a long time 

String s1=new String("test");  
System.out.println(s1==s1.intern());   //false
//"test" As a literal quantity , Put it in the pool , and new when s1 Pointing to heap New generation of string object ,s1.intern() Pointing to "test" Literal amount of string object generated in pool before 

String s2=new StringBuilder("abc").toString();
System.out.println(s2==s2.intern());  //false

Eight basic types of wrapper classes and object pools

java Most of the basic types of wrapper classes in have implemented constant pool technology ( Strictly speaking, it should be called object pool , On the pile ), These classes are Byte,Short,Integer,Long,Character,Boolean, The other two floating-point type wrapper classes are not implemented . in addition Byte,Short,Integer,Long,Character this 5 The packing class of an integer is only when the corresponding value is less than or equal to 127 The object pool can be used only when the object pool is used , That is, objects are not responsible for creating and managing 127 Objects of these classes . Because the probability of using this relatively small number is relatively large .

 //5 Plastic packaging Byte,Short,Integer,Long,Character The object of , 
        // When the value is less than 127 You can use the object pool  
        Integer i1 = 127;  // The underlying layer of this call is actually executed Integer.valueOf(127), It uses IntegerCache Object pool 
        Integer i2 = 127;
        System.out.println(i1 == i2);// Output true 

        // Greater than 127 when , No objects are taken from the object pool  
        Integer i3 = 128;
        Integer i4 = 128;
        System.out.println(i3 == i4);// Output false 
        
        // use new Keywords newly generated objects do not use object pools 
        Integer i5 = new Integer(127);  
        Integer i6 = new Integer(127);
        System.out.println(i5 == i6);// Output false 

        //Boolean Class also implements object pooling Technology  
        Boolean bool1 = true;
        Boolean bool2 = true;
        System.out.println(bool1 == bool2);// Output true 

        // Floating point wrapper classes don't implement object pooling  
        Double d1 = 1.0;
        Double d2 = 1.0;
        System.out.println(d1 == d2);// Output false 
原网站

版权声明
本文为[Please close your eyes when it is dark]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/162/202206110457584621.html