Parameter types for the JVM

JVM parameter types fall into three general categories:

  • Standard parameters, which are common to almost every JVM version, are relatively stable
  • X parameters, non-standardized parameters, vary somewhat from JVM version to JVM version, but vary slightly
  • The XX parameter is a non-standardized parameter, which is relatively unstable and varies greatly from JVM version to JVM version. It is mainly used for JVM tuning and debugging

Common standard parameters:

  • -help
  • -server
  • -client
  • -version
  • -showversion
  • -cp
  • -classpath

Common X parameters:

  • -Xint: Explains execution
  • -xcomp: compiles native code the first time it is used
  • -xmixed: This is the default mode in which the JVM decides whether to compile native code

The XX parameter is divided into two types: Boolean:

Format: -xx: [+ -] < name > Indicates whether to enable or disable the name attribute. For example, -xx :+UseConcMarkSweepGC indicates that UseConcMarkSweepGC is enabled. -xx :+UseG1GC indicates that UseG1GC is enabled

Key /value; key/value;

Format: -xx: < name > = < value > indicates that the value of the name attribute is value. -xx :MaxGCPauseMillis=500 Indicates that the value of the MaxGCPauseMillis attribute is 500. -xx :GCTimeRatio=19 Indicates that the value of the GCTimeRatio attribute is 19

The most common JVM arguments are -xmx to specify the size of the initial heap and -xms to specify the maximum size of the heap. Then there is the -xSS argument, which specifies the stack size of the thread. You can see that these three arguments all start with -x. Are they -x arguments? They are not. They are XX arguments, which are an abbreviation:

-xms is equivalent to -xx :InitialHeapSize -xmx is equivalent to -xx :MaxHeapSize -xss is equivalent to -xx :ThreadStackSize


View JVM runtime parameters

It is important to look at the JVM runtime parameters, because only when you know the current running parameter values will you know how to tune them. My server is running a Tomcat process. Let’s use this Tomcat process as an example. The pid of this process is 1200, as follows:

Commonly used to view JVM runtime parameters:

  • -xx :+PrintFlagsInitial Displays the initial value
  • -xx :+PrintFlagsFinal To view the final value
  • – XX: + UnlocakExperimentalVMOptions unlock experimental parameters
  • – XX: + UnlocakDiagnosticVMOptions unlock diagnostic parameters
  • -xx :+PrintCommandLineFlags Prints command line parameters

Let’s look at the -xx :+PrintFlagsInitial argument as follows:

[root@server ~]# java -XX:+PrintFlagsFinal -version
     bool UseCodeCacheFlushing                      = true                                {product}
     bool UseCompiler                               = true                                {product}
     bool UseCompilerSafepoints                     = true                                {product}
     bool UseCompressedClassPointers               := true                                {lp64_product}
     bool UseCompressedOops                        := true                                {lp64_product}Copy the code

-version is added because it should output version information at the end, otherwise it would output help information. The above is only a partial intercept of the content, the actual printed content is a lot, about more than 700 lines. As you can see, the truncated arguments are bool (among others) and have the symbols = and :=, which indicate the JVM default value, and :=, which indicate the value modified by the user or JVM, which is a non-default value.

Note: Using Java command + argument directly, you are actually viewing the JVM runtime parameter values of the current Java command.

This command is similar to the Linux ps command. It is also used to view the process, but JPS is specifically used to view the Java process. It is also easy to use:

  • JPS is a process for viewing hotspot virtual machines that have access to it. If you do not specify hostid, you can view the HOST JVM process by default. Otherwise, you can view the JVM process on the host specified by hostid. In this case, the JStatd service must be enabled on the host specified by hostid. JPS can list LVMID, main class name, main function parameters, JVM parameters, jar names, etc.

The following is a brief example of the common usage of the JPS command:

[root@server ~]# JPS Default lists process numbers and simple class or JAR names 1200 Bootstrap 2847 Jps [root@server ~]# Jps -l // Prints the full package name or jar name of the main class of the application. 2880 Sun. Tools. The JPS. The JPS 1200 org. Apache. Catalina. Startup. The Bootstrap/root @ server ~ # JPS - q / / show only process number, Don't show the jar, class, 1200 2901 [root@server ~]# JPS -m // Outputs the parameters passed in by the main function [root@server ~]# JPS -v // List the JVM parameters 1200 Bootstrap . - Djava. Util. Logging. Config file = / home/tomcat, apache tomcat -- 8.5.8 / conf/logging properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 - Djava. Protocol. The handler. PKGS = org. Apache. Catalina. Webresources - Dcatalina. Base = / home/tomcat, apache tomcat -- 8.5.8 - Dcatalina. Home = / home/tomcat, apache tomcat - 8.5.8 - Djava. IO. Tmpdir = / home/tomcat, apache tomcat - 2921 the Jps 8.5.8 / temp - Dapplication. Home = / usr/Java/jdk1.8.0 _111 - Xms8m root @ server ~ #Copy the code

For more information, see the official documentation for the JPS command:

Docs.oracle.com/javase/8/do…

If we need to view the JVM parameters of a runtime Java process, we can use the jinfo command. Jinfo is a JDK built-in command that can be used to view the extended parameters of a running Java application and even modify some of the parameters at run time. Here’s a quick example of how the jinfo command is commonly used:

[root@server ~]# jinfo-flag MaxHeapSize 1200 // Check the maximum memory size of the Java process -xx :MaxHeapSize=482344960 [root@server ~]# jinfo-flag UseConcMarkSweepGC 1200 // Check whether the UseConcMarkSweepGC garbage collector is used. -xx: -useconcMarkSweepGC [root@server ~]# jinfo-flag UseG1GC -xx: -useg1GC [root@server ~]# jinfo -flag UseParallelGC 1200 // Check whether the UseG1GC garbage collector is used 1200 Garbage collector -xx: -useParallelGC [root@server ~]# jinfo -flag PrintGC 1200 // Check whether PrintGC -xx: -printgc [root@server ~]# Jinfo-flag +PrintGC 1200 [root@server ~]# jinfo-flag-printgc 1200-xx :+PrintGC [root@server ~]# jinfo-flag-printgc 1200 // [root@server ~]# jinfo-flags 1200 // check the Attaching to process ID 1200, please wait... Debugger Attached successfully. Server Compiler detected. JVM version is 25.111-B14 non-default VM Flags: -XX:CICompilerCount=2 -XX:InitialHeapSize=31457280 -XX:MaxHeapSize=482344960 -XX:MaxNewSize=160759808 -XX:MinHeapDeltaBytes=196608 -XX:NewSize=10485760 -XX:OldSize=20971520 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops Command line: . - Djava. Util. Logging. Config file = / home/tomcat, apache tomcat -- 8.5.8 / conf/logging properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 - Djava. Protocol. The handler. PKGS = org. Apache. Catalina. Webresources - Dcatalina. Base = / home/tomcat, apache tomcat -- 8.5.8 - Dcatalina. Home = / home/tomcat, apache tomcat - 8.5.8 - Djava. IO. Tmpdir = / home/tomcat, apache tomcat - 8.5.8 / temp/root @ server ~ #Copy the code

For more information, see the official documentation for the jinfo command:

Docs.oracle.com/javase/8/do…


Jstat views JVM statistics

Jstat is used to monitor hotspot-based JVMS for real-time command line statistics on their heap usage. Jstat can be used to monitor specific JVMS as follows:

  • Class loading and unloading
  • View garbage collection information
  • Check the capacity and usage of new generation, old generation and durable generation
  • View garbage collection for new generation, old generation, and persistent generation, including the number of garbage collections and the time taken for garbage collection
  • To investigate the capacity and distribution of Eden and Survior in Cenozoic
  • View JIT compilation information

The official document address is as follows:

Docs.oracle.com/javase/8/do…

Options for viewing class loading and unloading:

Option Displays
-class Class loading behavior statistics

-class Indicates the statistics on class loading behavior. Example:

[root@server ~]# jstat -class 1200 1000 3 Loaded Bytes Unloaded Time 3249 6451.6 0 0.0 2.40 3249 6451.6 0 0.0 2.40 3249 6451.6 0 0.0 2.40 [root@server ~]#Copy the code

Command description:

  • -class Displays the loading and unloading of a class
  • 1200 Specifies the PROCESS ID
  • 1000 Specifies how many milliseconds to view it once
  • 3 Specifies how many times to view, that is, how many lines to output

Description of the printed information:

  • Loaded Indicates the number of Loaded classes
  • Bytes Indicates the size of the loaded class
  • Number of Unloaded classes
  • Bytes Size of space occupied by unmounted classes
  • Time Time spent performing class load and unload operations

Options for viewing garbage collection information:

Option Displays
-gc Garbage collection heap behavior statistics
-gcutil Overview of garbage collection statistics (percent)
-gccause Overview of garbage collection statistics (same as -gcutil)
-gcnew Cenozoic behavior statistics
-gcold Behavior statistics of old age and Metaspace region
-gccapacity The capacity of each garbage collection generation (young,old, PERM) and their corresponding spatial statistics
-gcnewcapacity Statistics of the new generation and its corresponding memory space
-gcoldcapacity Behavior statistics of the aged generation
-gcmetacapacity Metaspace area size statistics

-gc Collects heap behavior statistics. Example:

[root@server ~]# jstat -gc 1200
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
1024.0 1024.0  0.0    35.2   8192.0   4826.9   20480.0    17994.0   20864.0 20268.3 2432.0 2238.1     29    0.134   0      0.000    0.134
[root@server ~]# Copy the code

The output shows that C is Capacity and U is Used:

  • S0C: total capacity of survivor0
  • S1C: survivor1 Indicates the total capacity of the zone
  • S0U: survivor0 Used capacity
  • S1C: survivor1 Used capacity of the zone
  • EC: total capacity of Eden
  • EU: Used capacity in Eden
  • OC: total capacity of the Old area
  • OU: used capacity of the Old sector
  • MC: Total capacity of the current Metaspace area (KB)
  • MU: Usage of Metaspace area (KB)
  • CCSC: Compressed total class space
  • CCSU: Compressed class space usage
  • YGC: The number of garbage recycling in the new generation
  • YGCT: New generation garbage recycling time
  • FGC: the number of garbage collections in the old years
  • FGCT: Old age garbage collection time
  • GCT: Total garbage collection time

Note: I am using JDK1.8 here, if it is a different version of the JDK, the information printed in this section will be a little different

JVM memory structure map (JDK1.8) :

– gcCapacity Capacity of each garbage collection generation (young,old, perM) and their corresponding space statistics. (same as -gc, which also prints the maximum and minimum space used by each region of the Java heap), example command:

[root@server ~]# jstat -gccapacity 1200
 NGCMN    NGCMX     NGC     S0C   S1C       EC      OGCMN      OGCMX       OGC         OC       MCMN     MCMX      MC     CCSMN    CCSMX     CCSC    YGC    FGC 
 10240.0 156992.0  10240.0 1024.0 1024.0   8192.0    20480.0   314048.0    20480.0    20480.0      0.0 1067008.0  20864.0      0.0 1048576.0   2432.0     29     0
[root@server ~]# Copy the code

Description of the printed information:

  • NGCMN: Minimum space occupied by the New generation
  • NGCMX: The largest space occupied by the New generation
  • OGCMN: The minimum space occupied by the old age
  • OGCMX: The maximum space occupied by the old era
  • OGC: Capacity of the current generation (KB)
  • OC: Space of the current generation (KB)
  • MCMN: Minimum space occupied by Metaspace
  • MCMX: Maximum space occupied by Metaspace

-gcutil Overview of garbage collection statistics (same as -GC, which prints the percentage of total space used). Command example:

[root@server ~]# jstat -gcutil 1200 S0 S1 O M CCS YGC YGCT FGC FGCT GCT 0.00 3.44 90.53 87.86 97.14 92.03 29 0.134 0 0.000 / root @ server ~ # 0.134Copy the code

-gCCause Overview of garbage collection statistics (same as -gcutil), plus the cause of the last two garbage collection events). Command example:

[root@server ~]# jstat -gccause 1200s0 S1 E O M CCS YGC YGCT FGC FGCT GCT LGCC GCC 0.00 3.44 92.49 87.86 97.14 92.03 29 0.134 0 0.000 0.134 Allocation Failure No GC [root@server ~]#Copy the code

Description of the printed information:

  • LGCC: The cause of recent garbage collection
  • GCC: The reason for the current garbage collection

-gcnew (statistics on the behavior of the new generation). Command example:

[root@server ~]# jstat -gcnew 1200
 S0C    S1C    S0U    S1U   TT MTT  DSS      EC       EU     YGC     YGCT  
1024.0 1024.0    0.0   35.2 15  15  512.0   8192.0   7738.1     29    0.134
[root@server ~]# Copy the code

Description of the printed information:

  • TT: Tenuring Threshold
  • MTT: Maximum Tenuring threshold
  • DSS: Size of survivor zone (KB)

– gcnewCapacity (Statistics on the new generation and its corresponding memory space). Command example:

[root@server ~]# jstat -gcnewcapacity 1200
  NGCMN      NGCMX       NGC      S0CMX     S0C     S1CMX     S1C       ECMX        EC      YGC   FGC 
   10240.0   156992.0    10240.0  15680.0   1024.0  15680.0   1024.0   125632.0     8192.0    29     0
[root@server ~]# Copy the code

Description of the printed information:

  • NGC: Current young generation capacity (KB)
  • S0CMX: maximum S0 space (KB)
  • S0C: current S0 space (KB)
  • ECMX: Maximum Eden space (KB)
  • EC: Current Eden space (KB)

-Gcold (Old age and Metaspace zone behavior statistics). Command example:

[root@server ~]# jstat -gcold 1200
   MC       MU      CCSC     CCSU       OC          OU       YGC    FGC    FGCT     GCT   
 20864.0  20268.3   2432.0   2238.1     20480.0     17994.0     29     0    0.000    0.134
[root@server ~]# Copy the code

– gcoldCapacity (statistics on the memory capacity of the old age). Command example:

[root@server ~]# jstat -gcoldCapacity 1200 OGCMN OGCMX OGC OC YGC FGC FGCT GCT 20480.0 314048.0 20480.0 20480.0 20480.0 29 0 0.000 / root @ server ~ # 0.134Copy the code

– gcMetacapacity (statistics of Metaspace area and its corresponding memory space). Command example:

[root@server ~]# jstat -gcmetacapacity 1200
   MCMN       MCMX        MC       CCSMN      CCSMX       CCSC     YGC   FGC    FGCT     GCT   
       0.0  1067008.0    20864.0        0.0  1048576.0     2432.0    30     0    0.000    0.136
[root@server ~]# Copy the code

Options for viewing JIT compilation information:

Option Displays
-compiler HotSpt JIT compiler behavior statistics
-printcompilation HotSpot compile method statistics

– Compiler HotSpt JIT compiler behavior statistics. Example:

[root@server ~]# jstat - Compiler 1200 Compiled Failed Invalid Time FailedType FailedMethod 2332 1 0 4.80 1 org/apache/tomcat/util/IntrospectionUtils setProperty [root@server ~]#Copy the code

Description of the printed information:

  • Compiled: indicates the number of compilations
  • Failed: indicates the number of compilation failures
  • Invalid: indicates the Invalid quantity
  • Time: indicates the compilation Time
  • FailedType: indicates the failure type
  • FailedMethod: fully qualified name of the FailedMethod

-printcompilation HotSpot compilation method statistics, example command:

[root@server ~]# jstat -printcompilation 1200
Compiled  Size  Type Method
    2332      5    1 org/apache/tomcat/util/net/SocketWrapperBase getEndpoint
[root@server ~]# Copy the code

Description of the printed information:

  • Compiled: Indicates the number of compilation tasks executed
  • Size: The number of bytes in the method bytecode
  • Type: compilation Type
  • Method: The class name and Method name of the compiled Method. Class names use “/” instead of “.” as spatial separators. The method name is the method name of the given class. The format is consistent with HotSpot -XX:+PrintComplation option

Demonstrate memory overflow in heap and non-heap areas

We all know that a project deployed online cannot directly modify its code or shut down or restart the service at will, so when an overflow error occurs, we need to use monitoring tools to analyze the cause of the error. So this section briefly demonstrates memory leaks in JVM heap and non-heap areas, and then we use tools to analyze the causes of memory leaks. First, create a SpringBoot project using IDEA. The directory structure of the project is as follows:

I’ve only checked Web and Lombok here and added ASM dependencies because we need asm to dynamically generate class files when demonstrating non-heap memory overflows. So the following dependencies are configured in the POM.xml file:

<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId>  </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> < the groupId > org. Projectlombok < / groupId > < artifactId > lombok < / artifactId > < version > 1.16.22 < / version > < / dependency > <dependency> <groupId> <artifactId> <version>3.3.1< version> </dependency> </dependencies>Copy the code

To demonstrate that the heap is running out of memory, we need to set the JVM memory parameter value in order to make the memory run out faster. As follows:

1.

2,

Create an entity class. Since objects are stored in the heap, we need to have an entity object to make a memory overflow. The code is as follows:

package org.zero01.monitor_tuning.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
}Copy the code

Then create a Controller class to test with tools like Postman. The code is as follows:

package org.zero01.monitor_tuning.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.zero01.monitor_tuning.vo.User; import java.util.ArrayList; import java.util.List; import java.util.UUID; /** * @program: Monitor_tuning * @description: Demo memory overflow interface * @author: 01 * @create: 2018-07-08 15:41 **/ @restController Public Class MemoryController {// Member variables of an object are stored on the heap along with the object itself  = new ArrayList<>(); -xmx32m -xMS32m ** @return */ @getMapping ("/heap") public String heap() {int I = 0; Userlist.add (new User(i++, uuid.randomuuid ().tostring ()))); }}}Copy the code

Start SpringBoot and accesslocalhost:8080/heapThe console output error log is as follows:

After demonstrating a heap overflow, let’s look at a non-heap overflow, which in JDK1.8 is Metaspace, as you can see from the previous JVM memory structure diagram. Also, to make memory overflow faster, we need to set the JVM’s Metaspace parameters as follows:

The Metaspace section can store classes, so we make the Metaspace section run out of memory by constantly storing classes. Using the ASM framework, you can create class files dynamically. Create a new Metaspace class with the following code:

package org.zero01.monitor_tuning.loader; import java.util.ArrayList; import java.util.List; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * @program: monitor_author: /** * @program: monitor_author: 01 * @create: 2018-07-08 15:58 **/ public class Metaspace extends ClassLoader {/** * public class Metaspace extends ClassLoader ** @return */ public static List<Class<? >> createClasses() {// Class holds List<Class<? >> classes = new ArrayList<Class<? > > (); // Loop 1000W times to generate 1000W different classes. for (int i = 0; i < 10000000; ++i) { ClassWriter cw = new ClassWriter(0); // Define a Class named Class{I}, whose access domain is public, and whose parent Class is java.lang.object, Do not implement any interface Cw. visit(opcodes. V1_1, opcodes. ACC_PUBLIC, "Class" + I, NULL, "Java /lang/Object", null); Visitor MW = cw.visitMethod(opcodes.acc_public, "<init>", "()V", null, null); // The first command is to load this mW.visitvarinsn (opcodes.aload, 0); Mw.visitmethodinsn (opcodes.invokespecial, "Java /lang/Object", "<init>", "()V"); // Return mw. VisitInsn (opcodes.return); mw.visitMaxs(1, 1); mw.visitEnd(); Metaspace test = new Metaspace(); byte[] code = cw.toByteArray(); // Define Class<? > exampleClass = test.defineClass("Class" + i, code, 0, code.length); classes.add(exampleClass); } return classes; }}Copy the code

Add a member variable and a method to the MemoryController class to create a non-heap memory overflow. The code is as follows:

package org.zero01.monitor_tuning.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.zero01.monitor_tuning.loader.Metaspace; import org.zero01.monitor_tuning.vo.User; import java.util.ArrayList; import java.util.List; import java.util.UUID; /** * @program: Monitor_tuning * @description: Demo memory overflow interface * @author: 01 * @create: 2018-07-08 15:41 **/ @RestController public class MemoryController { private List<User> userList = new ArrayList<>(); Private List< class <? >> classList = new ArrayList<>(); -xmx32m -xMS32m ** @return */ @getMapping ("/heap") public String heap() {int I = 0; while (true) { userList.add(new User(i++, UUID.randomUUID().toString())); }} /** * show the non-heap memory overflow interface * set JVM parameters: -XX:MetaspaceSize=32M -XX:MaxMetaspaceSize=32M * @return */ @GetMapping("/nonheap") public String nonHeap() { int i = 0;  While (true) {// The Metaspace section overflows the classlist.addall (metaspace.createclasses ()); }}}Copy the code

Start SpringBoot and accesslocalhost:8080/nonheapThe console output error log is as follows:


Export the memory image file

In the previous section, we demonstrated two types of memory overflows, heap and non-heap. What should we do if our online project has this kind of memory overflow error? We typically analyze memory image files to see which classes are holding up memory.

There are several ways to export memory image files:

  • First: the memory at the time the JVM automatically export, this way you need to set up the following two JVM parameters: – XX: XX: + HeapDumpOnOutOfMemoryError – HeapDumpPath. = /
  • Second: manual export using jmap command, we usually use this method, because it is too late to export when memory overflow occurs, we should try to prevent errors

Note: -xx :HeapDumpPath=./ is used to specify the path to which to export the memory image file

We will first demonstrate the first way to export the memory image file. Again, we need to set the JVM parameters as follows:

Start SpringBoot and accesslocalhost:8080/heapThe memory image file is exported to the root directory of the current project:

Open the project root directory and you will see this memory image file:

Next, we will demonstrate the use of jmap command to export memory image files as follows:

C:\Users\admin\Desktop> JPS // Check the process PID 10328 JPS 1100 Launcher 12124 1308 MonitorTuningApplication C:\Users\admin\Desktop>jmap -dump:format=b,file=heap.hprof 1308 C:\Users\admin\Desktop\heap.hprof ... Heap dump file created C:\Users\admin\Desktop>Copy the code

Command options:

  • -dump Exports memory image files
  • Format Specifies the binary format of the file
  • File Specifies the name of the file. By default, the file is exported to the current path

Since the current path is on the desktop, it is exported to the desktop:

To learn more about the use of Jmap, you can refer to the official documentation at the following address:

Docs.oracle.com/javase/8/do…


Use the MAT tool to analyze memory overflow

In the previous section, we demonstrated two ways to export memory image files. But what’s inside these memory image files? How can we use memory image files to analyze the problem? And that’s where another tool, MAT, comes in.

Memory Analyzer Tools MAT is an Eclipse Memory analysis tool. Its official website is as follows:

www.eclipse.org/mat/

The download address of MAT is as follows:

www.eclipse.org/mat/downloa…

Once downloaded and decompressed, clicking MemoryAnalyzer.exe opens the tool without opening Eclipse, although Eclipse is included in the downloaded zip package:

After normal opening, the interface is as follows:

Then we open the memory image file that the JVM automatically exports when a memory overflow occurs as shown earlier:





After the memory image file is opened, MAT will automatically analyze a pie chart, which lists three possible problems and divides the pie into three parts. Problem Suspect 1 indicates the most likely cause of the Problem, and you can see that it does point to the MemoryController class that we demonstrated running out of memory. As also described above, an instance of this class takes up 55.57% of the memory:

This makes it very easy to find the problem, but it’s certainly not so easy in an online environment. After all, this was a deliberate memory overflow, which would have been more complicated in a real production environment.

So we do more analysis, such as looking at the number of instance objects for all classes:

The User class has more than 100,000 instance objects. The User class has more than 100,000 instance objects.

Right click on the object in question to see its strong reference:

The MemoryController contains a member variable of the set type named userList, which holds more than 100,000 User instances. This basically confirms the problem with the userList in the MemoryController:

You can also view the number of bytes of an object in the same way you view the number of objects:

The common functions of MAT are introduced here. Generally, we can already locate the problem by using these common functions, and this graphical tool is easy to use, so there is no further description here.


Jstack and thread state

Jstack, which prints all thread data within the JVM, is a thread stack tracing tool that comes with the Java VIRTUAL Machine. When you print thread stack information using JStack, you can redirect the information to a file, creating a snapshot of the JVM’s threads at the current time. A thread snapshot is a collection of the stack of methods being executed by each thread in the current JVM. The main purpose of a thread snapshot is to locate the cause of long pauses, such as interthread deadlocks, dead loops, and long waits due to requests for external resources. By looking at the call stack of each thread when it pauses, you can see what the unresponsive thread is doing in the background, or what resources it is waiting for. If a Java program crashes to generate a core file, the JStack tool can be used to get information about the Java Stack and native stack of the core file, so you can easily know how the Java program crashed and where the problem occurred in the program. In addition, the JStack tool can attach to a running Java program and see information about the Java Stack and native Stack of the running Java program. Jstack is very useful if the current running Java program appears hung.

Jstack official document address is as follows:

Docs.oracle.com/javase/8/do…

Example of using jStack to print stack information for all threads in a Java program:

[root@server ~]# JPS 1200 Bootstrap 4890 JPS [root@server ~]# jStack 1200 // Add pid directly to print the stack information in the Java program 21:48:01 Full Thread Dump Java HotSpot(TM) 64-bit Server VM (25.111-B14 mixed mode): "Attach Listener" #35 daemon prio=9 os_prio=0 tid=0x00007fd944006000 nid=0xb90 waiting on condition [0x0000000000000000]  java.lang.Thread.State: RUNNABLE // The status of this thread is RUNNABLE "http-nio-8080-exec-10" #34 daemon prio=5 OS_PRIo =0 TID = 0x00007FD96c31e800 nID = 0x4D3 waiting  on condition [0x00007fd9487ac000] java.lang.Thread.State: Unsafe.park(Native Method) - parking to wait for <0x00000000edae5bb8> (a  java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039) at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442) at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:103) at org.apache.tomcat.util.threads.TaskQueue.take(TaskQueue.java:31) at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:745) ...Copy the code

Note: NID is the unique identifier of a thread. It is hexadecimal and is usually used to locate a thread

You can see that each of these threads has a java.lang.thread. State parameter, whose value is the State of the Thread.

Java thread status:

  • NEW A NEW thread that has not been started
  • RUNNABLE Specifies the running thread
  • BLOCKED is typically waiting for a resource to be locked
  • WAITING state
  • TIMED_WAITING Waiting state with time
  • The TERMINATED thread exits

Schematic diagram of thread state transition:


Jstack combats dead loops with deadlocks

In this section, we use an example to demonstrate dead loops and deadlocks, and then show you how to use JStack to analyze and locate problems.

In the Controller package, create a new CpuController class to demonstrate skyrocketing CPU usage when an infinite loop or deadlock occurs. This is code that parses JSON and doesn’t need to pay attention to the details of the code, except that accessing the interface causes an infinite loop. The code is as follows:

package org.zero01.monitor_tuning.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.ArrayList; import java.util.List; /** * @program: Monitor_tuning * @description: Display deadloops and deadlocks * @author: 01 * @create: 2018-07-08 22:14 **/ @restController public class CpuController {/** * @requestMapping ("/loop") public List<Long> loop() { String data = "{\"data\":[{\"partnerid\":]"; return getPartneridsFromJson(data); } public static List<Long> getPartneridsFromJson(String data) { //{\"data\":[{\"partnerid\":982,\"count\":\"10000\",\"cityid\":\"11\"},{\"partnerid\":983,\"count\":\"10000\",\"cityid\" : \ \ "11"}, {\ "partnerid \" : 984, \ "the count \" : \ "10000 \", \ "cityid \" : \ \ "11"}]} / / it is normal data List < Long > List = new ArrayList<Long>(2); if (data == null || data.length() <= 0) { return list; } int datapos = data.indexOf("data"); if (datapos < 0) { return list; } int leftBracket = data.indexOf("[", datapos); int rightBracket = data.indexOf("]", datapos); if (leftBracket < 0 || rightBracket < 0) { return list; } String partners = data.substring(leftBracket + 1, rightBracket); if (partners == null || partners.length() <= 0) { return list; } while (partners ! = null && partners.length() > 0) { int idpos = partners.indexOf("partnerid"); if (idpos < 0) { break; } int colonpos = partners.indexOf(":", idpos); int commapos = partners.indexOf(",", idpos); if (colonpos < 0 || commapos < 0) { //partners = partners.substring(idpos+"partnerid".length()); //1 continue; } String pid = partners.substring(colonpos + 1, commapos); if (pid == null || pid.length() <= 0) { //partners = partners.substring(idpos+"partnerid".length()); //2 continue; } try { list.add(Long.parseLong(pid)); } catch (Exception e) { throw new RuntimeException(e); } partners = partners.substring(commapos); } return list; }}Copy the code

Package the project using Maven and upload it to the server. The package command is as follows:

mvn clean package -Dmaven.test.skip=true

Upload the JAR package to the server and start it using the following command:

[root@server ~]# nohup java -jar monitor_tuning-0.0.1-SNAPSHOT.jar &Copy the code

Then use the browser to open several tabs to access the project interface, in order to make the CPU load faster:

Enter the top command on the Linux command line to check the CPU load. After a minute or two, you will find that the CPU load has increased as follows:

When the CPU of our server is heavily loaded like this, we can use the jStack command to locate which thread has the highest CPU usage. Print the stack information for the thread using the jstack command and redirect it to a file:

[root@server ~]# jstack 4999 > loop.txtCopy the code

Then use the top command to specify the threads in a process to view:

[root@server ~]# top -p 4999 -HCopy the code

The pid of the thread with the highest occupation rate can be seen from the above command.

Then use printf to convert the PID to a hexadecimal NID, where the pid is actually a decimal NID, as follows:

[root@server ~]# printf "%x" 5016
1398
[root@server ~]#Copy the code

After obtaining the NID, use vim command to open loop. TXT file and search the data of the thread by nID:

As mentioned above, by analyzing the thread stack information, we can locate the problem code in which method in which class. This is how to use the jStack command to locate the problem code.


Now that I’ve shown you how to locate code that has deadlock loops, I’ll show you how to use JStack to locate code that has deadlock loops. First, add the following code to the CpuController class:

private Object lock1 = new Object(); private Object lock2 = new Object(); /** */ @requestMapping ("/ DEADLOCK ") public String DEADLOCK (){new Thread(()->{synchronized(lock1) {try {Thread.sleep(1000); }catch(Exception e) {} synchronized(lock2) { System.out.println("Thread1 over"); } } }) .start(); new Thread(()->{ synchronized(lock2) { try {Thread.sleep(1000); }catch(Exception e) {} synchronized(lock1) { System.out.println("Thread2 over"); } } }) .start(); return "deadlock"; }Copy the code

After adding the above code, re-package it using the Maven command.

Go back to the server, kill the previously started service, and delete the old JAR package:

[root@server ~]# JPS 4999 jar 5103 JPS [root@server ~]# kill -9 4999 // Kill process [root@server ~]# rm -rf Monitor_tuning-0.0.1 - snapshot. jar // Deletes the previous JAR packageCopy the code

After deleting the old jar package, upload the new jar package again, and run the jar package as before using the following command:

[root@server ~]# nohup java -jar monitor_tuning-0.0.1-SNAPSHOT.jar &Copy the code

The main thread will not be affected by the deadlock because it is the child thread that has deadlock:

So how do we locate the code in which the deadlock occurred? Because deadlock in this case is not the same as an infinite loop, it does not cause CPU load rates to skyrocket. So we can’t locate the problem code that way, but the nice thing about JStack is that it automatically finds deadlocks for us. As before, generate a thread snapshot file using the following command:

[root@server ~]# jps
5128 jar
5177 Jps
[root@server ~]# jstack 5128 > deadlock.txt
[root@server ~]# vim deadlock.txtCopy the code

When you open the file using Vim and navigate directly to the end of the file, you can see the deadlock information, which JStack automatically finds and places at the end. I’ve highlighted the lock where two threads are waiting for each other in blue and red boxes: