preface

In real enterprise Java development, we sometimes encounter the following problems:

1.OutOfMemoryError, insufficient memory

2. Memory leaks

3. The thread deadlocks

Key Contention for Lock Contention

5.Java processes consume too much CPU

.

These problems may be ignored by many people in daily development (for example, some people just restart the server or increase the memory without getting to the root of the problem), but being able to understand and solve these problems is a prerequisite for Java programmers to advance. This article will introduce some of the most commonly used JVM performance tuning monitoring tools in the hope of providing some inspiration. This article referred to a lot of information on the Internet, it is difficult to list one by one, here to express gratitude to the author of these information! For information on JVM performance tuning, see the end of this article.

A, JPS (Java Virtual Machine Process Status Tool)

JPS is mainly used to output information about the status of processes running in the JVM. The syntax is as follows:

jps [options] [hostid]
Copy the code

If you do not specify hostid, the default value is the current host or server.

The command line parameters are described as follows:

-q Does not output the class name, Jar name, or parameters passed to main. -m Outputs the parameters passed to main. -l Outputs the full name of the main class or JarCopy the code

For example:

Root @ ubuntu: / # JPS - m - l 2458 org. Artifactory. Standalone. Main. The main/usr/local/artifactory -- 2.2.5 / etc/jetty. The XML 29920 com.sun.tools.hat.Main -port 9998 /tmp/dump.dat 3149 org.apache.catalina.startup.Bootstrap start 30972 sun.tools.jps.Jps  -m -l 8247 org.apache.catalina.startup.Bootstrap start 25687 com.sun.tools.hat.Main -port 9999 dump.dat 21711 mrf-center.jarCopy the code

B、 jstack

Jstack is used to view stack information about threads in a Java process. The syntax is as follows:

Jstack [option] pid jstack [option] Executable core jstack [option] [server-id@]remote-hostname-or- IP The command line parameters are described as follows:

Listing: -l long listings will display additional lock information in the event of a deadlock using jstack -l PID to keep track of lock holdings -m mixed mode will display Java stack information. Jstack also outputs C/C++ stack information (such as Native methods). Jstack can locate the thread stack, and from the stack information we can locate specific code, so it is used a lot in JVM performance tuning. Here is an example to find the most cpu-consuming Java thread in a Java process and locate the stack information using the commands ps, top, printf, jstack, and grep.

The first step is to find the Java process ID. The name of the Java application I have deployed on the server is MRF-Center:

root@ubuntu:/# ps -ef | grep mrf-center | grep -v grep root 21711 1 1 14:47 pts/3 00:02:10 java -jar mrf-center.jar Ps-lfp pid or ps-mp pid -o THREAD, tid, time, or top-HP PID.

The TIME column is the CPU TIME consumed by each Java thread. The longest CPU TIME is used by the thread whose ID is 21742

printf "%x\n" 21742
Copy the code

We get 21742 with a hex value of 54ee, which we’ll use next.

Jstack is used to output the stack information for process 21711, and grep from the hexadecimal value of the thread ID as follows:

root@ubuntu:/# jstack 21711 | grep 54ee
"PollIntervalRetrySchedulerThread" prio=10 tid=0x00007f950043e000 nid=0x54ee in Object.wait() [0x00007f94c6eda000]
Copy the code

Can see CPU consumption in PollIntervalRetrySchedulerThread Object of this class. The wait (), I was looking for under my code, orientation to the following code:

// Idle wait getLog().info("Thread [" + getName() + "] is idle waiting..." ); schedulerThreadState = PollTaskSchedulerThreadState.IdleWaiting; long now = System.currentTimeMillis(); long waitTime = now + getIdleWaitTime(); long timeUntilContinue = waitTime - now; synchronized(sigLock) { try { if(! halted.get()) { sigLock.wait(timeUntilContinue); } } catch (InterruptedException ignore) { } }Copy the code

It is the idle wait code for the polling task, and siglock. wait(timeUntilContinue) corresponds to object.wait ().

C, JMAP (Memory Map), and JHAT (Java Heap Analysis Tool)

Jmap is used to check heap memory usage, usually in combination with JHAT.

Jmap syntax is as follows:

jmap [option] pid
jmap [option] executable core
jmap [option] [server-id@]remote-hostname-or-ip
Copy the code

If you are running on a 64-bit JVM, you may need to specify the -j-d64 command option parameter.

jmap -permstat pid
Copy the code

Print the class loader of the process and the persistent generation object information loaded by the class loader, output: class loader name, whether the object is alive (unreliable), object address, parent class loader, loaded class size and other information, as shown below:

Use jmap-heap PID to view process heap memory usage, including the GC algorithm used, heap configuration parameters, and heap memory usage in each generation. Take the following example:

root@ubuntu:/# jmap -heap 21711 Attaching to process ID 21711, please wait... Debugger attached successfully. Server Compiler detected. JVM version is 20.10-B01 using Ththread -local Object allocation.  Parallel GC with 4 thread(s) Heap Configuration: MinHeapFreeRatio = 40 MaxHeapFreeRatio = 70 MaxHeapSize = 2067791872 (1972.0MB) NewSize = 1310720 (1.25MB) MaxNewSize = 17592186044415 MB OldSize = 5439488 (5.1875MB) NewRatio = 2 SurvivorRatio = 8 PermSize = 21757952 (20.75MB) MaxPermSize = 85983232 (82.0MB) Heap Usage: PS Young Generation Eden Space: Capacity = 6422528 (6.125MB) Used = 5445552 (5.1932830810546875MB) Free = 976976 (0.9317169189453125MB) 84.78829520089286%, informs the From Space: Capacity = 131072 (0.125MB) Used = 98304 (0.09375MB) Free = 32768 (0.03125MB) 75.0% Used To Space: Capacity = 131072 (0.125MB) Used = 0 (0.0MB) Free = 131072 (0.125MB) 0.0% Used PS Old Generation Capacity = 35258368 (33.625MB) Used = 4119544 (3.9287033081054688MB) Free = 31138824 (29.69629669189453MB) 11.683876009235595% Used PS Perm Generation capacity = 52428800 (50.0MB) Used = 26075168 (24.867218017578125MB) Free = 26353632 (25.13278198242421875 MB) 49.73443603515625%, informs...Copy the code

Jmap-histo [:live] pid = jmap-histo [:live] pid = jmap-histo [:live] pid

root@ubuntu:/# jmap -histo:live 21711 | more

 num     #instances         #bytes  class name
----------------------------------------------
   1:         38445        5597736  <constMethodKlass>
   2:         38445        5237288  <methodKlass>
   3:          3500        3749504  <constantPoolKlass>
   4:         60858        3242600  <symbolKlass>
   5:          3500        2715264  <instanceKlassKlass>
   6:          2796        2131424  <constantPoolCacheKlass>
   7:          5543        1317400  [I
   8:         13714        1010768  [C
   9:          4752        1003344  [B
  10:          1225         639656  <methodDataKlass>
  11:         14194         454208  java.lang.String
  12:          3809         396136  java.lang.Class
  13:          4979         311952  [S
  14:          5598         287064  [[I
  15:          3028         266464  java.lang.reflect.Method
  16:           280         163520  <objArrayKlassKlass>
  17:          4355         139360  java.util.HashMap$Entry
  18:          1869         138568  [Ljava.util.HashMap$Entry;
  19:          2443          97720  java.util.LinkedHashMap$Entry
  20:          2072          82880  java.lang.ref.SoftReference
  21:          1807          71528  [Ljava.lang.Object;
  22:          2206          70592  java.lang.ref.WeakReference
  23:           934          52304  java.util.LinkedHashMap
  24:           871          48776  java.beans.MethodDescriptor
  25:          1442          46144  java.util.concurrent.ConcurrentHashMap$HashEntry
  26:           804          38592  java.util.HashMap
  27:           948          37920  java.util.concurrent.ConcurrentHashMap$Segment
  28:          1621          35696  [Ljava.lang.Class;
  29:          1313          34880  [Ljava.lang.String;
  30:          1396          33504  java.util.LinkedList$Entry
  31:           462          33264  java.lang.reflect.Field
  32:          1024          32768  java.util.Hashtable$Entry
  33:           948          31440  [Ljava.util.concurrent.ConcurrentHashMap$HashEntry;
Copy the code

Class name is an object type, described as follows:

B byte C char D double F float I int J long Z Boolean [array, e.g. [I denotes int[] [L+ class name other objectCopy the code

Another common scenario is to dump the process memory usage into a file using Jmap and then analyze it using JHAT. The jmap dump command is in the following format:

jmap -dump:format=b,file=dumpFileName pid
Copy the code

Dump (ID: 21711);

root@ubuntu:/# jmap -dump:format=b,file=/tmp/dump.dat 21711     
Dumping heap to /tmp/dump.dat ...
Heap dump file created
Copy the code

Dump files can be viewed with MAT, VisualVM and other tools, here using JHAT to view:

root@ubuntu:/# jhat -port 9998 /tmp/dump.dat
Reading from /tmp/dump.dat...
Dump file created Tue Jan 28 17:46:14 CST 2014
Snapshot read, resolving...
Resolving 132207 objects...
Chasing references, expect 26 dots..........................
Eliminating duplicate references..........................
Snapshot resolved.
Started HTTP server on port 9998
Server is ready.
Copy the code

Jhat -j -xmx512m -port 9998 / TMP /dump.dat if the Dump file is too large, you may need to add -j -xmx512m to specify maximum heap memory. Then you can enter the host address :9998 in the browser to view:

The last item supports OQL (Object Query Language).

**D, **jstat (JVM Statistics Monitoring Tool)

The syntax is as follows:

jstat [ generalOption | outputOptions vmid [interval[s|ms] [count]] ]
Copy the code

The vmID is the ID of a Java VIRTUAL machine (VM). On Linux/Unix, it is generally the ID of a process. Interval is the sampling interval. Count is the number of samples. For example, the following output is GC information, sampling interval is 250ms, sampling number is 4:

root@ubuntu:/# jstat -gc 21711 250 4 S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT 192.0 192.0 64.0 0.0 6144.0 1854.9 32000.0 4111.6 55296.0 25472.7 702 0.431 3 0.218 0.649 192.0 192.0 64.0 0.0 6144.0 1972.2 32000.0 4111.6 55296.0 25472.7 702 0.431 3 0.218 0.649 192.0 192.0 64.0 0.0 6144.0 1972.2 32000.0 4111.6 55296.0 25472.7 702 0.431 3 0.218 0.649 192.0 192.0 64.0 0.0 6144.0 2109.7 32000.0 4111.6 55296.0 25472.7 702 0.431 3 0.218 0.649 192.0 64.0 0.0 6144.0 2109.7 32000.0 4111.6 55296.0 25472.7 702 0.431 3 0.218 0.649Copy the code

To see what the above columns mean, look at the JVM heap memory layout:

As can be seen:

Heap memory = Young generation + Old generation + Permanent generation Young generation = Eden region + two Survivor regions (From and To)Copy the code

Now explain the meaning of each column:

S0C, S1C, S0U, and S1U: Survivor 0/1 Capacity and usage EC, EU: Eden Capacity and usage OC, OU: Capacity and usage of the elderly generation PC, PU: Capacity and usage of the permanent generation YGC, YGT: Young GC count and GC duration FGC and FGCT: Full GC count and Full GC duration GCT: total GC durationCopy the code

**E, ** Hprof (Heap/CPU Profiling Tool)

Hprof is able to show CPU usage and statistics on heap memory usage.

The syntax is as follows:

java -agentlib:hprof[=options] ToBeProfiledClass
java -Xrunprof[:options] ToBeProfiledClass
javac -J-agentlib:hprof[=options] ToBeProfiledClass
Copy the code

The full command options are as follows:

Option Name and Value Description Default --------------------- ----------- ------- heap=dump|sites|all heap profiling all cpu=samples|times|old CPU usage off monitor=y|n monitor contention n format=a|b text(txt) or binary output a file=<file> write data to file java.hprof[.txt] net=<host>:<port> send data over a socket off depth=<size> stack trace The depth interval = 4 > < ms sample interval in 10 ms cutoff = < value > output cutoff point 0.0001 lineno = y | n line number in traces? y thread=y|n thread in traces? n doe=y|n dump on exit? y msa=y|n Solaris micro state accounting n force=y|n force output to <file> y verbose=y|n print messages about dumps yCopy the code

Here are some examples from the official guide.

Sample CPU Usage Sampling Profiling(CPU =samples) :

java -agentlib:hprof=cpu=samples,interval=20,depth=3 Hello
Copy the code

Sample CPU consumption every 20 milliseconds, stack depth 3, and generate a profile named java.hprofe.txt in the current directory.

Example of CPU Usage Times Profiling(CPU = Times), which can obtain more fine-grained CPU consumption information than the CPU Usage Sampling Profile, down to the beginning and end of each method call, It is implemented using bytecode injection (BCI) :

javac -J-agentlib:hprof=cpu=times Hello.java
Copy the code

Example of Heap Allocation Profiling(Heap = Sites) :

javac -J-agentlib:hprof=heap=sites Hello.java
Copy the code

An example of Heap Dump(Heap = Dump), which generates more detailed Heap Dump information than the above Heap Allocation Profiling:

javac -J-agentlib:hprof=heap=dump Hello.java
Copy the code

Although adding the -xrunprof :heap=sites parameter to the JVM startup parameter can generate a CPU/ heap Profile, it has a significant impact on JVM performance and is not recommended for online server environments.

The last

I here organized a: JVM related data material documentation, JVM brain map, Spring family barrel series, Java systematic information, (including Java core knowledge, interview topics and the latest 20 years of the Internet, e-books, etc.) friends who need to pay attention to the public number [procedure Yuan Small wan] can be obtained.