# jdk版本
[root@localhost ~]# java -version
java version "1.8.0_271"
Java(TM) SE Runtime Environment (build 1.8.0_271-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.271-b09, mixed mode)
一、 jps(Java Virtual Machine Process Status Tool):基础工具
jps主要用来输出JVM中运行的进程状态信息。
- 语法
jps [options] [hostid]
- 参数
参数 | 说明 |
---|---|
-q | 不输出类名、Jar名和传入main方法的参数 |
-m | 输出传入main方法的参数 |
-l | 输出main类或Jar的全限名 |
-v | 输出传入JVM的参数 |
- 示例
[root@localhost ~]# jps -ml
11252 test-jvm.jar
11579 sun.tools.jps.Jps -ml
二、 jstack
jstack主要用来查看某个Java进程内的线程堆栈信息。jstack可以定位到线程堆栈,根据堆栈信息我们可以定位到具体代码,也经常用来排除死锁情况,所以它在JVM性能调优中使用得非常多。
- 语法
jstack [option] pid
jstack [option] executable core
jstack [option] [server-id@]remote-hostname-or-ip
- 参数
参数 | 说明 |
---|---|
-F | 当正常输出的请求不被响应时,强制输出线程堆栈 |
-m | 如果调用到本地方法的话,可以显示C/C++的堆栈 |
-l | 除堆栈外,显示关于锁的附加信息,在发生死锁时可以用jstack -l pid来观察锁持有情况 |
- 示例
[root@localhost ~]# jstack 26563
.............省略
"http-nio-8080-exec-1" #13 daemon prio=5 os_prio=0 tid=0x00007f66fca4f800 nid=0x67d1 runnable [0x00007f66d85be000]
java.lang.Thread.State: RUNNABLE
at top.dongxibao.demo.controller.TestJvm.testJstack1(TestJvm.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
.............省略
三、 jmap(Memory Map)和 jhat(Java Heap Analysis Tool)
jmap可以查看堆内存的初始化信息以及堆内存的使用情况,还可以生成dump文件来进行详细分析。然后使用jhat来进行分析
- 语法
jmap [option] pid
jmap [option] executable core
jmap [option] [server-id@]remote-hostname-or-ip
- 参数
参数 | 说明 |
---|---|
heap | 显示Java堆详细信息 |
histo[:live] | 显示堆中对象的统计信息 |
clstats | 打印类加载器信息 |
finalizerinfo | 显示在F-Queue队列等待Finalizer线程执行finalizer方法的对象 |
dump:<dump-options> | 生成堆转储快照 |
- 示例
查看堆栈信息
[root@localhost ~]# jmap -heap 27111
Attaching to process ID 27111, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.271-b09
using thread-local object allocation.
Mark Sweep Compact GC
Heap Configuration:
MinHeapFreeRatio = 40
MaxHeapFreeRatio = 70
MaxHeapSize = 104857600 (100.0MB)
NewSize = 34930688 (33.3125MB)
MaxNewSize = 34930688 (33.3125MB)
OldSize = 69926912 (66.6875MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
New Generation (Eden + 1 Survivor Space):
capacity = 31457280 (30.0MB)
used = 16189512 (15.439521789550781MB)
free = 15267768 (14.560478210449219MB)
51.46507263183594% used
Eden Space:
capacity = 27983872 (26.6875MB)
used = 13296472 (12.680503845214844MB)
free = 14687400 (14.006996154785156MB)
47.514768506659834% used
From Space:
capacity = 3473408 (3.3125MB)
used = 2893040 (2.7590179443359375MB)
free = 580368 (0.5534820556640625MB)
83.29110775353773% used
To Space:
capacity = 3473408 (3.3125MB)
used = 0 (0.0MB)
free = 3473408 (3.3125MB)
0.0% used
tenured generation:
capacity = 69926912 (66.6875MB)
used = 9052064 (8.632720947265625MB)
free = 60874848 (58.054779052734375MB)
12.945036097118088% used
11274 interned Strings occupying 938016 bytes.
生成堆转储快照dump文件并使用jhat查看
[root@localhost ~]# jmap -dump:format=b,file=/tmp/dump.dat 27111
Dumping heap to /tmp/dump.dat ...
Heap dump file created
# -J-Xmx512m限定最大内存
[root@localhost ~]# jhat -J-Xmx512m -port 9999 /tmp/dump.dat
Reading from /tmp/dump.dat...
Dump file created Sat Nov 28 17:41:33 CST 2020
Snapshot read, resolving...
Resolving 194937 objects...
Chasing references, expect 38 dots......................................
Eliminating duplicate references......................................
Snapshot resolved.
Started HTTP server on port 9999
Server is ready.
四、jstat(JVM统计监测工具)
可以检测Java程序运行的实时情况,包括堆内存信息和垃圾回收信息,我们常常用来查看程序垃圾回收情况。
- 语法
jstat [ generalOption | outputOptions vmid [interval[s|ms] [count]] ]
- 常用命令
jstat -gc pid
信息字段
参数 | 说明 |
---|---|
S0C | 年轻代中 To Survivor 的容量(单位 KB) |
S1C | 年轻代中 From Survivor 的容量(单位 KB) |
S0U | 年轻代中 To Survivor 目前已使用空间(单位 KB) |
S1U | 年轻代中 From Survivor 目前已使用空间(单位 KB) |
EC | 年轻代中 Eden 的容量(单位 KB) |
EU | 年轻代中 Eden 目前已使用空间(单位 KB) |
OC | 老年代的容量(单位 KB) |
OU | 老年代目前已使用空间(单位 KB) |
MC | 元空间的容量(单位 KB) |
MU | 元空间目前已使用空间(单位 KB) |
YGC | 从应用程序启动到采样时年轻代中 gc 次数 |
YGCT | 从应用程序启动到采样时年轻代中 gc 所用时间 (s) |
FGC | 从应用程序启动到采样时 老年代(Full Gc)gc 次数 |
FGCT | 从应用程序启动到采样时 老年代代(Full Gc)gc 所用时间 (s) |
GCT | 从应用程序启动到采样时 gc 用的总时间 (s) |
- 示例
[root@localhost ~]# jstat -gc 27111
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
3392.0 3392.0 0.0 0.0 27328.0 1047.1 68288.0 11389.2 30080.0 28101.5 3968.0 3585.8 13 0.057 2 0.040 0.097
六、实例
1.内存泄漏
- Java测试代码
/**
* 模拟内存泄漏
*/
@GetMapping(value = "/memory/leak")
public String testMemoryLeak() {
System.out.println("模拟内存泄漏");
for (int i = 0; i < 5000; i++) {
ThreadLocal<Byte[]> localVariable = new ThreadLocal<Byte[]>();
// 为线程添加变量
localVariable.set(new Byte[4096 * 1024]);
}
return "ok";
}
- 运行项目访问接口
# 用命令行加上堆内存大小限制,同时设置内存溢出的时候输出堆栈快照并输出日志。
[root@localhost ~]# java -jar -Xms100m -Xmx100m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:/tmp/heaplog.log test-jvm.jar
[root@localhost ~]# curl localhost:8080/memory/leak
- 报错信息
java.lang.OutOfMemoryError: Java heap space
- 用
jstat -gc pid
命令来看看程序的GC情况
[root@localhost ~]# jstat -gc 27871
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
3392.0 3392.0 0.0 568.8 27328.0 27328.0 68288.0 55987.3 31232.0 29113.5 4096.0 3708.6 18 0.085 3 0.121 0.206
- 分析生成的
.hprof
文件
Windows下使用JDK自带Java Visual VM工具查看
eclipse插件MAT和idea插件jProfiler也可以分析
2.找出某个Java进程中最耗费CPU的Java线程并定位堆栈信息
- java测试代码
/**
* 测试jstack
*/
@GetMapping(value = "/cpu/loop")
public String testCpuLoop() {
while (true) {
//Do Nothing
}
}
- 运行项目访问接口
[root@localhost ~]# java -jar -Xms100m -Xmx100m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:/tmp/heaplog.log test-jvm.jar
[root@localhost ~]# curl localhost:8080/cpu/loop
- 查看进程id
[root@localhost ~]# jps
26563 jar
26589 Jps
-
根据进程id找到消耗CPU最高的线程
-
将消耗CPU最高的线程转成16进制
[root@localhost ~]# printf "%x" 26577
67d1
- jstack查找这个线程的信息
# -A 10表示查找到所在行的后10行
[root@localhost ~]# jstack 26563 | grep -A 10 67d1
"http-nio-8080-exec-1" #13 daemon prio=5 os_prio=0 tid=0x00007f66fca4f800 nid=0x67d1 runnable [0x00007f66d85be000]
java.lang.Thread.State: RUNNABLE
at top.dongxibao.demo.controller.TestJvm.testJstack1(TestJvm.java:51)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879)
参考文章