JDK itself provides many convenient JVM performance tuning and monitoring tools. In addition to the integrated VisualVM and jConsole, there are also small tools such as jps, jstack, jmap, jhat, and jstat. Can start to understand the common tools for JVM performance tuning.
In real enterprise Java development, sometimes we will encounter the following problems:
1. OutOfMemoryError, insufficient memory
2. Memory leak
3. Thread deadlock
4. Lock contention (Lock Contention)
5. The Java process consumes too much CPU
These problems may be overlooked by many people in daily development (for example, some people just restart the server or increase the memory when encountering the above problems, but will not get to the root of the problem), but it is an advanced Java programmer to understand and solve these problems. necessary requirements. This article will introduce some commonly used JVM performance tuning and monitoring tools, hoping to be useful. This article refers to a lot of information on the Internet, and it is difficult to list them one by one. I would like to express my gratitude to the authors of these materials! For information about JVM performance tuning, please refer to the end of this article.
A、 jps(Java Virtual Machine Process Status Tool)
jps is mainly used to output process status information running in the JVM. The syntax format is as follows:
jps [options] [hostid]
If no hostid is specified, it defaults to the current host or server.
The command line parameter options are described as follows:
-q Do not output the class name, Jar name and parameters passed into the main method -m Output the parameters passed into the main method -l Output the full name of the main class or Jar -v Output the parameters passed into the JVM
For example:
root@ubuntu:/# jps -m -l 2458 org.artifactory.standalone.main.Main /usr/local/artifactory-2.2.5/etc/jetty.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.jar
B、 jstack
jstack is mainly used to view the thread stack information in a Java process. The syntax format is as follows:
jstack [option] pid jstack [option] executable core jstack [option] [server-id@]remote-hostname-or-ip
The command line parameter options are described as follows:
-l long listings, will print out additional lock information, you can use jstack -l pid to observe the lock holding situation when a deadlock occurs -m mixed mode, not only output Java stack information, but also output C/C++ stack information (such as Native method)
jstack can locate the thread stack, and we can locate the specific code according to the stack information, so it is used a lot in JVM performance tuning. Let's take an example to find out the most CPU-consuming Java thread in a Java process and locate the stack information. The commands used are ps, top, printf, jstack, and grep.
The first step is to find out the Java process ID. The name of the Java application I 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
The process ID is 21711. The second step is to find the most CPU-consuming thread in the process. You can use ps -Lfp pid or ps -mp pid -o THREAD, tid, time or top -Hp pid. I use the third one here , the output is as follows:
The TIME column is the CPU time consumed by each Java thread. The thread with the longest CPU time is the thread whose thread ID is 21742. Use
printf "%x\n" 21742
The hexadecimal value of 21742 is 54ee, which will be used below.
OK, the next step is finally jstack's turn. It is used to output the stack information of process 21711, and then grep according to 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]
You can see that the CPU is consumed in the Object.wait() of the PollIntervalRetrySchedulerThread class. I found my code and located 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) { } }
It is the idle waiting code of the polling task. The above sigLock.wait(timeUntilContinue) corresponds to the previous Object.wait().
C、 jmap(Memory Map)和jhat(Java Heap Analysis Tool)
jmap is used to view the heap memory usage, usually combined with jhat.
The jmap syntax format is as follows:
jmap [option] pid jmap [option] executable core jmap [option] [server-id@]remote-hostname-or-ip
If running on a 64-bit JVM, you may need to specify the -J-d64 command option parameter.
jmap -permstat pid
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 in the figure 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. Like 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 thread-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% used 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.132781982421875MB) 49.73443603515625% used ....</pre>
Use jmap -histo[:live] pid to view the histogram of the number and size of objects in the heap memory. If you bring live, only live objects are counted, as follows:
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</pre>;
class name is the object type, described as follows:
B byte C char D double F float I int J long Z boolean [ array, such as [I means int[] [L+ class name other objects
Another very common situation is: use jmap to dump the process memory usage into a file, and then use jhat to analyze and view it. The format of jmap dump command is as follows:
jmap -dump:format=b,file=dumpFileName
I also performed Dump on the above process ID 21711:
root@ubuntu:/# jmap -dump:format=b,file=/tmp/dump.dat 21711 Dumping heap to /tmp/dump.dat ... Heap dump file created
The dumped files can be viewed with tools such as MAT, VisualVM, etc. Here, use 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.
Then you can enter the host address: 9998 in the browser to view:
You can explore the part in the red line above by yourself. The last item supports OQL (Object Query Language).
D. jstat (JVM statistical monitoring tool)
The syntax format is as follows:
jstat [ generalOption | outputOptions vmid [interval[s|ms] [count]] ]
vmid is the virtual machine ID, which is generally the process ID on Linux/Unix systems. interval is the sampling interval. count is the number of samples. For example, the following output is GC information, the sampling interval is 250ms, and the 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.2 18 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
To understand the meaning of the above columns, first look at the JVM heap memory layout:
As can be seen:
Heap memory = young generation + old generation + permanent generation Young generation = Eden area + two Survivor areas (From and To)
Now to explain the meaning of each column:
S0C, S1C, S0U, S1U: Survivor 0/1 area capacity (Capacity) and usage (Used) EC, EU: Eden area capacity and usage OC, OU: Old generation capacity and usage PC, PU: Permanent generation Capacity and usage YGC, YGT: Young generation GC times and GC time-consuming FGC, FGCT: Full GC times and Full GC time-consuming GCT: Total GC time-consuming
Other JVM performance tuning reference materials:
"Java Virtual Machine Specification"
《Java Performance》
《Trouble Shooting Guide for JavaSE 6 with HotSpot VM》: http://www.oracle.com/technetwork/java/javase/tsg-vm-149989.pdf
《Effective Java》
VisualVM: http://docs.oracle.com/javase/7/docs/technotes/guides/visualvm/
jConsole: http://docs.oracle.com/javase/1.5.0/docs/guide/management/jconsole.html
Monitoring and Managing JavaSE 6 Applications: http://www.oracle.com/technetwork/articles/javase/monitoring-141801.html