JVM 调优命令详解

本文详细介绍了JVM监控和诊断工具jmap与jstat的使用,包括查看堆内存分配、垃圾收集、内存泄漏检测等。通过jmap可以分析堆内存dump,了解对象分配及内存占用,而jstat则用于实时监控GC行为和内存使用情况。这些工具对于理解和优化Java应用的性能至关重要。
摘要由CSDN通过智能技术生成

jmap 命令

1)查看历史生成的实例 jmap -histo pid

一般可以将结果输出查看,会很方便
$ jmap -histo 16677 > ./log.txt
在这里插入图片描述
打开log.txt文件显示如下:
在这里插入图片描述

  • num:序号
  • instances:实例数量
  • bytes:占用空间大小
  • class name:类名称,[C is a char[],[S is a short[],[I is a int[],[B is a byte[],[[I is a int[][]

2)查看当前存活的实例 jmap -histo:live pid

执行过程中可能会触发一次full gc

3)堆信息 jmap -heap

$ jmap -heap 3334
Attaching to process ID 3334, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.131-b11

using thread-local object allocation.
Parallel GC with 4 thread(s)

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize              = 2147483648 (2048.0MB)
   NewSize                  = 44564480 (42.5MB)
   MaxNewSize               = 715653120 (682.5MB)
   OldSize                  = 89653248 (85.5MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 141557760 (135.0MB)
   used     = 126737968 (120.86674499511719MB)
   free     = 14819792 (14.133255004882812MB)
   89.53092221860533% used
From Space:
   capacity = 12058624 (11.5MB)
   used     = 0 (0.0MB)
   free     = 12058624 (11.5MB)
   0.0% used
To Space:
   capacity = 13107200 (12.5MB)
   used     = 0 (0.0MB)
   free     = 13107200 (12.5MB)
   0.0% used
PS Old Generation
   capacity = 101187584 (96.5MB)
   used     = 16652536 (15.881095886230469MB)
   free     = 84535048 (80.61890411376953MB)
   16.457094182622246% used

19181 interned Strings occupying 1940984 bytes.

Heap Configuration 堆的配置信息

Heap Configuration:
   MinHeapFreeRatio         = 0
   MaxHeapFreeRatio         = 100
   MaxHeapSize   堆的最大容量           = 2147483648 (2048.0MB) 
   NewSize       新生代空间             = 44564480 (42.5MB) 
   MaxNewSize    新生代最大空间          = 715653120 (682.5MB)
   OldSize       老年代空间             = 89653248 (85.5MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize 元空间           = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize  元空间最大容量       = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage 使用情况

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 141557760 (135.0MB)
   used     = 126737968 (120.86674499511719MB)
   free     = 14819792 (14.133255004882812MB)
   89.53092221860533% used
From Space:
   capacity = 12058624 (11.5MB)
   used     = 0 (0.0MB)
   free     = 12058624 (11.5MB)
   0.0% used
To Space:
   capacity = 13107200 (12.5MB)
   used     = 0 (0.0MB)
   free     = 13107200 (12.5MB)
   0.0% used
PS Old Generation
   capacity = 101187584 (96.5MB)
   used     = 16652536 (15.881095886230469MB)
   free     = 84535048 (80.61890411376953MB)
   16.457094182622246% used

4) 堆内存dump

jmap -dump:format=b,file=文件名 pid

$ jmap -dump:format=b,file=springboot.hprof 3334
Dumping heap to /Users/huoyajing/springboot.hprof ...
Heap dump file created

在这里插入图片描述

设置内存溢出自动导出

也可以设置内存溢出自动导出dump文件(内存很大的时候,可能会导不出来)

-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./ (路径)

实例代码:

-Xms10M -Xmx10M -XX:+PrintGCDetails
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=
/Users/huoyajing/information/springCloud/jvm/jvm1.dump

public class OOMTest {
	public static void main(String[] args) {
		// -Xms10M -Xmx10M -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/Users/huoyajing/information/springCloud/jvm/jvm1.dump
		List<Object> list = new ArrayList<>();
		long i = 0;
		long j = 0;
		while (true) {
			list.add(new User(i++, UUID.randomUUID().toString(), "1", 1, "0"));
			new User(j--, UUID.randomUUID().toString(), "1", 1, "0");
		}
	}
}
public class User {
	private Long id;

	private String name;

	private String password;

	private Integer type;

	private String status;

	public User(){

	}

	public User(Long id, String name, String password, int type, String status) {
		super();
		this.id=id;
		this.name=name;
		this.password=password;
		this.type=type;
		this.status=status;
	}

执行结果:

java.lang.OutOfMemoryError: Java heap space
Dumping heap to /Users/huoyajing/information/springCloud/jvm/jvm1.dump ...
Heap dump file created [13278771 bytes in 0.102 secs]
Heap
 PSYoungGen      total 2560K, used 2048K [0x00000007bfd00000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 2048K, 100% used [0x00000007bfd00000,0x00000007bff00000,0x00000007bff00000)
  from space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
  to   space 512K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007bff80000)
 ParOldGen       total 7168K, used 7132K [0x00000007bf600000, 0x00000007bfd00000, 0x00000007bfd00000)
  object space 7168K, 99% used [0x00000007bf600000,0x00000007bfcf72d8,0x00000007bfd00000)
 Metaspace       used 4235K, capacity 4668K, committed 4864K, reserved 1056768K
  class space    used 476K, capacity 492K, committed 512K, reserved 1048576K
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:3210)
	at java.util.Arrays.copyOf(Arrays.java:3181)
	at java.util.ArrayList.grow(ArrayList.java:261)
	at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
	at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
	at java.util.ArrayList.add(ArrayList.java:458)
	at com.huohuo.service.jvm.OOMTest.main(OOMTest.java:22)

在这里插入图片描述

jstat 命令

jstat命令可以查看堆内存各部分的使用量,以及加载类的数量。命令的格式如下:
jstat [-命令选项] [vmid] [间隔时间(毫秒)] [查询次数]
注意:使用的jdk版本是jdk8

1)垃圾回收统计 jstat -gc pid (最常用)

$ jstat -gc 16677
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT    CGC    CGCT     GCT
11776.0 3072.0  0.0   2720.0 41984.0  17226.5   104960.0   49804.8   56488.0 52498.3 9128.0 7787.2    147    2.308   9      1.730   -          -    4.038


S0C:第一个幸存区的大小,单位KB
S1C:第二个幸存区的大小
S0U:第一个幸存区的使用大小
S1U:第二个幸存区的使用大小
EC:eden的大小
EU:eden的使用大小
OC:old区大小
OU:old区使用大小
MC:元空间大小(元空间)
MU:元空间使用大小
CCSC:压缩类空间大小
CCSU:压缩类空间使用大小

注意:是从项目启动开始算起(而非本次命令)
YGC:年轻代垃圾回收次数
YGCT:年轻代垃圾回收消耗时间,单位s
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间,单位s
GCT:垃圾回收消耗总时间,单位s

可以执行命令 jstat -gc pid 1000 10 (每隔1秒执行1次命令,共执行10次),通过观察EU(eden区的使用)来估算每秒eden大概新增多少对象,如果系统负载不高,可以把频率1秒换成1分钟,甚至10分钟来观察整体情况。注意,一般系统可能有高峰期和日常期,所以需要在不同的时间分别估算不同情况下对象增长速率。
在这里插入图片描述

2)堆内存统计 jstat -gccapacity pid

jstat -gccapacity 33133
 NGCMN    NGCMX     NGC     S0C   S1C       EC      OGCMN      OGCMX       OGC         OC       MCMN     MCMX      MC     CCSMN    CCSMX     CCSC    YGC    FGC
 43520.0 698880.0 184832.0 11776.0 13312.0 155648.0    87552.0  1398272.0    93184.0    93184.0      0.0 1081344.0  35416.0      0.0 1048576.0   4608.0      8     2

NGCMN:新生代最小容量
NGCMX:新生代最大容量
NGC:当前新生代容量
S0C:第一个幸存区大小
S1C:第二个幸存区的大小
EC:伊甸园区的大小
OGCMN:老年代最小容量
OGCMX:老年代最大容量
OGC:当前老年代大小
OC:当前老年代大小
MCMN:最小元数据容量
MCMX:最大元数据容量
MC:当前元数据空间大小
CCSMN:最小压缩类空间大小
CCSMX:最大压缩类空间大小
CCSC:当前压缩类空间大小
YGC:年轻代gc次数
FGC:老年代GC次数

3)新生代垃圾回收统计 jstat -gcnew 33133

jstat -gcnew 33133
 S0C    S1C    S0U    S1U   TT MTT  DSS      EC       EU     YGC     YGCT
11776.0 13312.0    0.0    0.0  3  15 13312.0 155648.0 126169.2      8    0.087

S0C:第一个幸存区的大小
S1C:第二个幸存区的大小
S0U:第一个幸存区的使用大小
S1U:第二个幸存区的使用大小
TT:对象在新生代存活的次数
MTT:对象在新生代存活的最大次数
DSS:期望的幸存区大小
EC:伊甸园区的大小
EU:伊甸园区的使用大小
YGC:年轻代垃圾回收次数
YGCT:年轻代垃圾回收消耗时间

4)新生代内存统计 jstat -gcnewcapacity 33133

$ jstat -gcnewcapacity 33133
  NGCMN      NGCMX       NGC      S0CMX     S0C     S1CMX     S1C       ECMX        EC      YGC   FGC
   43520.0   698880.0   184832.0 232960.0  11776.0 232960.0  13312.0   697856.0   155648.0     8     2

NGCMN:新生代最小容量
NGCMX:新生代最大容量
NGC:当前新生代容量
S0CMX:最大幸存1区大小
S0C:当前幸存1区大小
S1CMX:最大幸存2区大小
S1C:当前幸存2区大小
ECMX:最大伊甸园区大小
EC:当前伊甸园区大小
YGC:年轻代垃圾回收次数
FGC:老年代回收次数

5)老年代垃圾回收统计 jstat -gcold 33133

$ jstat -gcold 33133
   MC       MU      CCSC     CCSU       OC          OU       YGC    FGC    FGCT     GCT
 35416.0  33776.2   4608.0   4287.8     93184.0     16535.5      8     2    0.112    0.199

MC:方法区大小
MU:方法区使用大小
CCSC:压缩类空间大小
CCSU:压缩类空间使用大小
OC:老年代大小
OU:老年代使用大小
YGC:年轻代垃圾回收次数
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间

6)老年代内存统计 jstat -gcoldcapacity 33133

jstat -gcoldcapacity 33133
   OGCMN       OGCMX        OGC         OC       YGC   FGC    FGCT     GCT
    87552.0   1398272.0     93184.0     93184.0     8     2    0.112    0.199

OGCMN:老年代最小容量
OGCMX:老年代最大容量
OGC:当前老年代大小
OC:老年代大小
YGC:年轻代垃圾回收次数
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间

7)元数据空间统计

$ jstat -gcmetacapacity 33133
   MCMN       MCMX        MC       CCSMN      CCSMX       CCSC     YGC   FGC    FGCT     GCT
       0.0  1081344.0    35416.0        0.0  1048576.0     4608.0     8     2    0.112    0.199

MCMN:最小元数据容量
MCMX:最大元数据容量
MC:当前元数据空间大小
CCSMN:最小压缩类空间大小
CCSMX:最大压缩类空间大小
CCSC:当前压缩类空间大小
YGC:年轻代垃圾回收次数
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间

8)总结:jstat -gc pid最为常用,可以看到相关的所有信息

jstack 命令

1)jstack pid 查看死锁

public class DeadLockTest {
	private static Object lock1 = new Object();
	private static Object lock2 = new Object();

	public static void main(String[] args) {
		new Thread(() -> {
			synchronized (lock1) {
				try {
					System.out.println("thread1 begin");
					Thread.sleep(5000);
				} catch (InterruptedException e) {
				}
				synchronized (lock2) {
					System.out.println("thread1 end");
				}
			}
		}).start();

		new Thread(() -> {
			synchronized (lock2) {
				try {
					System.out.println("thread2 begin");
					Thread.sleep(5000);
				} catch (InterruptedException e) {
				}
				synchronized (lock1) {
					System.out.println("thread2 end");
				}
			}
		}).start();

		System.out.println("main thread end");
	}
}

在这里插入图片描述
“Thread-1” 线程名
prio=5 优先级=5
tid=0x000000001fa9e000 线程id
nid=0x2d64 线程对应的本地线程标识nid
java.lang.Thread.State: BLOCKED 线程状态

在这里插入图片描述

还可以使用jvisualvm检测死锁。

2)线上CPU飙升了怎么办?jstack可以找出占用cpu最高的线程堆栈信息

  1. 使用命令top -p ,显示你的java进程的内存情况,pid是你的java进程号,比如19663
  2. 按H,获取每个线程的内存情况
  3. 找到内存和cpu占用最高的线程tid,比如19664(一个进程可能有多个线程)
  4. 转为十六进制得到 0x4cd0,此为线程id的十六进制表示
  5. 执行 jstack 19663|grep -A 10 4cd0,得到线程堆栈信息中 4cd0 这个线程所在行的后面10行,从堆栈中可以发现导致cpu飙高的调用方法
    注:十六进制都是小写,找到该对应线程下文10行相关信息
    nid=0x2d64 线程对应的本地线程标识nid
    在这里插入图片描述

jvisualvm命令工具

1)导入dump文件进行分析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
通过分析可以看到问题所在,char[]数组和String以及Long多,估计就是对象创建导致的,本身String底层就是Char数组。(实例则是上方堆内存dump)
在这里插入图片描述

2)检测死锁

实例见上文的jstack命令
在这里插入图片描述
3)抽样器使用
在这里插入图片描述
在这里插入图片描述
抽样器可以结合内存抽样和CPU抽样,结合一起找到问题。详情使用后期会针对实际例子来讲解。

总结

  • 通过jmap查看JVM中各个区域的使用情况
  • 通过jstack查看线程的运行情况,比如线程阻塞,死锁
  • 通过jstat查看垃圾回收的情况,尤其fullgc,若频繁fullgc,就得发现问题解决问题,进行调优了。

本地能复现的问题我们可以通过命令或者jvisualvm来进行查看,线上我们则可以使用阿里开源工具Arthas,详情点击这里 实数太方便了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值