写点什么

面试还不懂 JVM 调优,看这篇文章就够了!

  • 2022-11-11
    湖南
  • 本文字数:2995 字

    阅读完需:约 10 分钟

面试还不懂JVM调优,看这篇文章就够了!

作为 Java 开发人员,我们肯定知道 JDK 的 bin 目录下有"java.exe"、"javac.exe"这两个命令工具,这也是我们平时用得最多的工具。但其实 bin 目录下还有很多工具,这些工具可以帮助我们进行 JVM 的调优,帮我们定位找出应用程序运行中产生的问题。下面我们来看看其中一些调优工具。

前置启动程序

​ 先启动一个 web 应用程序,然后用各种 JDK 自带命令优化应用。

jps

jps					
复制代码

​ 用 jps 查看应用进行 ID



jinfo

jinfo -flags 92604
复制代码

​ 此命令可以实时查看和调整虚拟机各项参数。



jmap

​ 此命令可以用来查看内存信息,实例个数以及占用大小,还可以生成堆转储快照。



jmap -histo 14660  #查看历史生成的实例jmap -histo:live 14660  #查看当前存活的实例,执行过程中可能会触发一次full gc
复制代码

打开 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[][]

堆信息

​ 可以查看当前应用的堆具体配置、使用信息。

jmap -heap 92604
复制代码



相关视频推荐:JVM调优实战

转储堆内存 dump

jmap -dump:format=b,file=web.hprof 92604
复制代码



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

  1. -XX:+HeapDumpOnOutOfMemoryError

  2. -XX:HeapDumpPath=./ (路径)

示例代码:

public class OOMTest {
public static List<Object> list = new ArrayList<>();
// JVM设置     // -Xms10M -Xmx10M -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\jvm.dump public static void main(String[] args) { List<Object> list = new ArrayList<>(); int i = 0; int j = 0; while (true) { list.add(new User(i++, UUID.randomUUID().toString())); } }}
复制代码

jvisualvm

jvisualvm
复制代码

​ 该命令可以打开一个可视化界面,监视当前运行应用程序、dump 文件进行故障分析等功能。

​ 导入上面示例代码运行后产生的 hprof 文件,可以看到 User 对象实例数名列前茅。



jstack

​ 此命令可以用来跟踪 Java 堆栈信息。用于生成虚拟机当前试课的线程快照。快照可以定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等都是导致线程长时间停顿的常见原因。

死锁示例

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"); }}
复制代码


jstack 100516
复制代码



"Thread-1":线程名

prio=5: java 线程优先级

os_prio:操作系统线程优先级

nid=0x18688 线程对应的本地线程标识 nid

java.lang.Thread.State: BLOCKED 线程状态



还可以用 jvisualvm 自动检测到死锁。



找出占用 cpu 最高的线程堆栈信息

public class Math {
public static final int initData = 666; public static User user = new User();
public int compute() { //一个方法对应一块栈帧内存区域 int a = 1; int b = 2; int c = (a + b) * 10; return c; }
public static void main(String[] args) { Math math = new Math(); while (true){ math.compute(); } }}

复制代码

1,使用命令 top -p ,显示你的 java 进程的内存情况,pid 是你的 java 进程号,比如 18963



2,按 H,获取每个线程的内存情况



3,找到内存和 cpu 占用最高的线程 tid,比如 18964

4,转为十六进制得到 0x4a14,此为线程 id 的十六进制表示

5,执行 jstack 18963|grep -A 10 4a14,得到线程堆栈信息中 4cd0 这个线程所在行的后面 10 行,从堆栈中可以发现导致 cpu 飙高的调用方法



6,查看对应的堆栈信息找出可能存在问题的代码

jstat

jstat 命令可以查看堆内存各部分的使用量,以及加载类的数量。命令的格式如下:

jstat [-命令选项] [vmid] [间隔时间(毫秒)] [查询次数]

注意:使用的 jdk 版本是 jdk8

整体 GC 压力情况(常用)

jstat -gc 103784 2000 1000
复制代码

​ 可以评估程序内存使用及 GC 压力整体情况,监控 gc,每 2000ms 打印输出一次,输出 1000 次。



  • S0C:第一个幸存区的大小,单位 KB

  • S1C:第二个幸存区的大小

  • S0U:第一个幸存区的使用大小

  • S1U:第二个幸存区的使用大小

  • EC:伊甸园区的大小

  • EU:伊甸园区的使用大小

  • OC:老年代大小

  • OU:老年代使用大小

  • MC:方法区大小(元空间)

  • MU:方法区使用大小

  • CCSC:压缩类空间大小

  • CCSU:压缩类空间使用大小

  • YGC:年轻代垃圾回收次数

  • YGCT:年轻代垃圾回收消耗时间,单位 s

  • FGC:老年代垃圾回收次数

  • FGCT:老年代垃圾回收消耗时间,单位 s

  • GCT:垃圾回收消耗总时间,单位 s

堆内存统计

jstat -gccapacity 103784
复制代码



  • NGCMN:新生代最小容量

  • NGCMX:新生代最大容量

  • NGC:当前新生代容量

  • S0C:第一个幸存区大小

  • S1C:第二个幸存区的大小

  • EC:伊甸园区的大小

  • OGCMN:老年代最小容量

  • OGCMX:老年代最大容量

  • OGC:当前老年代大小

  • OC:当前老年代大小

  • MCMN:最小元数据容量

  • MCMX:最大元数据容量

  • MC:当前元数据空间大小

  • CCSMN:最小压缩类空间大小

  • CCSMX:最大压缩类空间大小

  • CCSC:当前压缩类空间大小

  • YGC:年轻代 gc 次数

  • FGC:老年代 GC 次数

新生代垃圾回收统计

jstat -gcnew 103784
复制代码



新生代内存统计

jstat -gcnewcapacity 103784
复制代码



  • NGCMN:新生代最小容量

  • NGCMX:新生代最大容量

  • NGC:当前新生代容量

  • S0CMX:最大幸存 1 区大小

  • S0C:当前幸存 1 区大小

  • S1CMX:最大幸存 2 区大小

  • S1C:当前幸存 2 区大小

  • ECMX:最大伊甸园区大小

  • EC:当前伊甸园区大小

  • YGC:年轻代垃圾回收次数

  • FGC:老年代回收次数

老年代垃圾回收统计

jstat -gcold 103784
复制代码



老年代内存统计

jstat -gcoldcapacity 103784
复制代码



元数据空间统计

jstat -gcmetacapacity 103784
复制代码



  • MCMN:最小元数据容量

  • MCMX:最大元数据容量

  • MC:当前元数据空间大小

  • CCSMN:最小压缩类空间大小

  • CCSMX:最大压缩类空间大小

  • CCSC:当前压缩类空间大小

  • YGC:年轻代垃圾回收次数

  • FGC:老年代垃圾回收次数

  • FGCT:老年代垃圾回收消耗时间

  • GCT:垃圾回收消耗总时间

总结

​ 上面介绍到的各个命令,都是 JDK 提供给我们的最基础的调优工具,如果还有功能更好的,那也是基于上面的基础功能进行开发封装。所以我们只要理解会用上面的各个命令,调优也不是什么问题。

原文:https://www.cnblogs.com/process-h/p/16877478.html

如果感觉本文对你有帮助,点赞关注支持一下,想要了解更多 Java 后端,大数据,算法领域最新资讯可以关注我公众号【架构师老毕】私信 666 还可获取更多 Java 后端,大数据,算法 PDF+大厂最新面试题整理+视频精讲

用户头像

需要资料添加小助理vx:bjmsb1226 2021-10-15 加入

爱生活爱编程

评论

发布
暂无评论
面试还不懂JVM调优,看这篇文章就够了!_程序员_Java全栈架构师_InfoQ写作社区