JVM调优与工具命令
JVM调优工具
- 前置启动程序
- JPS
- JMAP
- 查看堆信息
- 堆内存dump
- 用jvisualvm命令工具导入该dump文件分析
- Jstack
- 用jvisualvm自动检测死锁
- jstack找出占用cpu最高的线程堆栈信息
- Jinfo
- 查看JVM的参数
- 查看java系统参数
- Jstat
- 垃圾回收统计
- 堆内存统计
- 新生代垃圾回收统计
- 新生代内存统计
- 老年代垃圾回收统计
- 老年代内存统计
- 元数据空间统计
- JVM运行情况预估
- 年轻代对象增长速率
- Young GC的触发频率和每次耗时
- 每次Young GC后有多少对象存活和进入老年代
- Full GC的触发频率和每次耗时
- 系统频繁Full GC导致系统卡顿是怎么回事
- 内存泄露到底是怎么回事
前置启动程序
事先启动一个Web应用程序,用JPS查看其进程ID,接着用各种JDK自带命令优化引用;
JPS
JMAP
可以用来查看内存信息,实例个数以及占用内存大小
用法1:JMAP -histo Java进程ID
控制台显示进程里内存的使用情况;
用户2:JMAP -histo Java进程ID > 文件路径
将JVM的内存使用情况输出到某个文件中;
运行Java程序,将内存使用情况输入到log.txt中;
JMAP -histo 14660 > ./log.txt
内容如下:
- num:序号
- instances:实力数量
- bytes:占用空间大小
- class name:类名称;[C 为char[] ,[B 为byte[] ,[S 为short[], [[I 为int[][];
查看堆信息
- JMAP -heap 进程号
- JMAP -heap 进程号 > 文件路径
- 查看所有进程
- 查看堆信息
Attaching to process ID 11120, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.144-b01using thread-local object allocation.
Parallel GC with 8 thread(s)
//堆参数的设置
Heap Configuration:MinHeapFreeRatio = 0MaxHeapFreeRatio = 100//最大堆容量MaxHeapSize = 2118123520 (2020.0MB)//年轻代大小NewSize = 44564480 (42.5MB)MaxNewSize = 705691648 (673.0MB)//老年代大小OldSize = 89653248 (85.5MB)NewRatio = 2SurvivorRatio = 8MetaspaceSize = 21807104 (20.796875MB)CompressedClassSpaceSize = 1073741824 (1024.0MB)MaxMetaspaceSize = 17592186044415 MBG1HeapRegionSize = 0 (0.0MB)Heap Usage:
PS Young Generation
//Eden区使用了32M
Eden Space:capacity = 34078720 (32.5MB)used = 10127792 (9.658615112304688MB)free = 23950928 (22.841384887695312MB)29.71881573016827% used
From Space:
//From区使用0Mcapacity = 5242880 (5.0MB)used = 0 (0.0MB)free = 5242880 (5.0MB)0.0% used
//TO区使用0M
To Space:capacity = 5242880 (5.0MB)used = 0 (0.0MB)free = 5242880 (5.0MB)0.0% used
PS Old Generation
//old区使用0Mcapacity = 89653248 (85.5MB)used = 0 (0.0MB)free = 89653248 (85.5MB)0.0% used1816 interned Strings occupying 161432 bytes.
堆内存dump
JMAP -dump:format=b, file=文件名 进程号
示例:
也可以设置内存溢出自动导出dump文件(内存很大的时候,可能会导不出来)
- -XX:+HeapDumpOnOutOfMemoryError
- -XX:HeapDumpPath=./ (路径)
示例代码:
package com.jvm.jvm1;import java.util.ArrayList;
import java.util.List;
import java.util.UUID;public class OOMTest {public static List<Object> list=new ArrayList<>();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()));new User(j--,UUID.randomUUID().toString());}}
}
运行:
用jvisualvm命令工具导入该dump文件分析
1)概要信息
2)类信息
Jstack
查看死锁;
jstack 进程ID
示例代码:
package com.jvm.jvm1;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("Abegin");Thread.sleep(4000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (lock2){System.out.println("Aend");}}}).start();new Thread(()->{synchronized (lock2){try {System.out.println("Bbegin");Thread.sleep(4000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (lock1){System.out.println("Bend");}}}).start();}
}
检测到了死锁
- Thread-1:线程名
- prio=5 优先级=5
- tid=0x000000001aa0d800 线程ID
- nid=0x1a70 线程对应的本地线程标识
- java.lang.Thread.State:BLOCKED 线程状态
用jvisualvm自动检测死锁
jstack找出占用cpu最高的线程堆栈信息
示例代码
package com.jvm.jvm1;public class Math {public static final int initData=555;public static User user=new User();public static int count=0;public static int compute(){User user2=new User();int a=1;int b=2;int c= (a+b) *10;int d=(a+b)*20;return c;}public static void main(String[] args){while(true){compute();}}
}
- Linux 使用命令top -p ,显示你的java进程的内存情况,pid是你的java进程号 比如19663
- 按住H,获取每个线程的内存情况
- 找到内存和CPU占用最高的线程TID,比如19664
- 转为十六进制0x4cd0 ,为线程ID的十六进制表示
- 执行jstack 19663 | grep -A 10 4cd0
得到线程堆栈信息中4cd0这个线程所在行的后面10行,从堆栈中可以发现导致CPU飙高的调用方法;
- 查看对应堆栈信息找出可能存在的问题代码
Jinfo
查看正在运行的Java应用程序的扩展参数
查看JVM的参数
jinfo -flags 进程名
E:\新建文件夹 (4)\jvm>jinfo -flags 1856
Attaching to process ID 1856, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.144-b01
Non-default VM flags: -XX:CICompilerCount=4 -XX:InitialHeapSize=1258291200 -XX:MaxHeapSize=1258291200 -XX:MaxNewSize=419430400 -XX:MinHeapDeltaBytes=524288 -XX:NewSize=419430400 -XX:OldSize=838860800 -XX:+UseCompressedClassPoi
nters -XX:+UseCompressedOops -XX:+UseFastUnorderedTimeStamps -XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
Command line: -Xmx1200m -Xms1200m -javaagent:E:\IDEA2017\IntelliJ IDEA 2017.3.5\lib\idea_rt.jar=41998:E:\IDEA2017\IntelliJ IDEA 2017.3.5\bin -Dfile.encoding=UTF-8
查看java系统参数
jinfo -sysprops 进程号
Jstat
查看堆内存各部分的使用情况,以及加载类的数量。
jstat [-命令选项] [vmid] [间隔时间(毫秒)] [查询次数]
垃圾回收统计
jstat -gc 进程ID:评估程序内存使用以及GC压力情况
E:\新建文件夹 (4)\jvm>jstat -gc 1856S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
51200.0 51200.0 0.0 0.0 307200.0 24576.1 819200.0 0.0 4480.0 770.4 384.0 75.9 0 0.000 0 0.000 0.000
- S0C :第一个幸存者区的大小,单位为KB
- S1C :第二个幸存者区大小
- S0U: 第一个幸存者区使用大小
- S1U:第二个幸存者区使用大小
- EC:Eden区大小
- EU:Eden区使用大小
- OC:老年代大小
- OU:老年代使用大小
- MC:元空间大小
- MU:元空间使用大小
- CCSC:压缩类空间大小
- CCSU:压缩类空间使用大小
- YGC:年轻代垃圾回收次数、
- YGCT:年轻代垃圾回收消耗时间,单位s
- FUC:老年代垃圾回收次数
- FUCT:老年代垃圾回收消耗时间,单位s
- GCT:垃圾回收总耗时间,单位s
堆内存统计
jstat -gccapacity 进程编号
E:\新建文件夹 (4)\jvm>jstat -gccapacity 15172NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC
409600.0 409600.0 409600.0 51200.0 51200.0 307200.0 819200.0 819200.0 819200.0 819200.0 0.0 1056768.0 4480.0 0.0 1048576.0 384.0 0 0
- NGCMN:新生代最小容量
- NGCMX:新生代最大容量
- NGC:当前新生代容量
- S0C:第一个幸存者区大小
- S1C:第二个幸存者去大小
- EC:Eden区大小
- OGCMN:老年代最小容量
- OGCMX:老年代最大容量
- OGC:当前老年代大小
- MCMN:元空间最小容量
- MCMX:元空间最大容量
- MC:元空间当前大小
- CCSMN:最小压缩类空间大小
- CCSMX:最大压缩类空间大小
- CCSC:当前压缩类空间大小
- YGC:年轻代GC次数
- FGC:老年代GC次数
新生代垃圾回收统计
jstat -gcnew 进程ID
- S0C :第一个幸存者区的大小,单位为KB
- S1C :第二个幸存者区大小
- S0U: 第一个幸存者区使用大小
- S1U:第二个幸存者区使用大小
- TT:对象在新生代存活的次数
- MTT:对象在新生代存活的最大次数
- DSS:期望的Eden大小
- EC:Eden区大小
- EU:Eden区使用大小
- YGC:年轻代垃圾回收次数
- YGCT:年轻代垃圾回收消耗时间
新生代内存统计
jstat -gcnewcapacity 进程编号
E:\新建文件夹 (4)\jvm>jstat -gcnewcapacity 15172NGCMN NGCMX NGC S0CMX S0C S1CMX S1C ECMX EC YGC FGC409600.0 409600.0 409600.0 136192.0 51200.0 136192.0 51200.0 408576.0 307200.0 0 0
- NGCMN:新生代最小容量
- NGCMX:新生代最大容量
- NGC:当前新生代容量
- S0CMX:最大幸存1区大小
- S0C:当前幸存1区大小
- S1CMX:最大幸存2区大小
- S1C:当前幸存2区大小
- ECMX:最大伊甸园区大小
- EC:当前伊甸园区大小
- YGC:年轻代垃圾回收次数
- FGC:老年代回收次数
老年代垃圾回收统计
jstat -gcold 进程ID
E:\新建文件夹 (4)\jvm>jstat -gcold 12956MC MU CCSC CCSU OC OU YGC FGC FGCT GCT17024.0 16363.6 2176.0 1957.2 87552.0 119.1 2 0 0.000 0.009
- MC:方法区大小
- MU:方法区使用大小
- CCSC:压缩类容量大小
- CCSU:压缩类使用大小
- OC:老年代容量
- OU:老年代使用大小
- YGC:年轻代垃圾回收次数
- FGC:老年代垃圾回收次数
- FGCT:老年代垃圾回收消耗时间
- GCT:垃圾回收消耗总时间
老年代内存统计
- OGCMN:老年代最小容量
- OGCMX:老年代最大容量
- OGC:当前老年代大小
- OC:老年代大小
- YGC:年轻代垃圾回收次数
- FGC:老年代垃圾回收次数
- FGCT:老年代垃圾回收消耗时间
- GCT:垃圾回收消耗总时间
元数据空间统计
- MCMN:最小元数据容量
- MCMX:最大元数据容量
- MC:当前元数据空间大小
- CCSMN:最小压缩类空间大小
- CCSMX:最大压缩类空间大小
- CCSC:当前压缩类空间大小
- YGC:年轻代垃圾回收次数
- FGC:老年代垃圾回收次数
- FGCT:老年代垃圾回收消耗时间
- GCT:垃圾回收消耗总时间
JVM运行情况预估
用jstat -gc -pid命令可以计算出一些关键数据,有了这些数据就可以采用之前介绍过的优化思路,先给自己的系统设置一些初始性的JVM参数,比如堆内存大小,年轻代大小,Eden与S区的比例,老年代大小,大对象阈值,元空间大小等
年轻代对象增长速率
可以执行命令jstat -gc pid 1000 10 (每一秒执行一次命令,共10次),通过观察EU来估算每秒Eden去大概新增多少对象,如果系统负载不高,可以换成10秒,或者1分钟来观察整体情况。一般系统会有高峰期和日常器,需要在不同时间分别估算不同对象增长速率;
Young GC的触发频率和每次耗时
知道年轻代对象增长速率我们就能推根据eden区的大小推算出Young GC大概多久触发一次,Young GC的平均耗时可以通过 YGCT/YGC 公式算出,根据结果我们大概就能知道系统大概多久会因为Young GC的执行而卡顿多久
每次Young GC后有多少对象存活和进入老年代
这个因为之前已经大概知道Young GC的频率,假设是每5分钟一次,那么可以执行命令 jstat -gc pid 300000 10 ,观察每次结果eden, survivor和老年代使用的变化情况,在每次gc后eden区使用一般会大幅减少,survivor和老年代都有可能增长,这些增长的对象就是每次 Young GC后存活的对象,同时还可以看出每次Young GC后进去老年代大概多少对象,从而可以推算出老年代对象增长速率。
Full GC的触发频率和每次耗时
知道了老年代对象的增长速率就可以推算出Full GC的触发频率了,Full GC的每次耗时可以用公式 FGCT/FGC 计算得出。
优化思路其实简单来说就是尽量让每次Young GC后的存活对象小于Survivor区域的50%,都留存在年轻代里。尽量别让对象进入老年 代。尽量减少Full GC的频率,避免频繁Full GC对JVM性能的影响。
系统频繁Full GC导致系统卡顿是怎么回事
- 机器配置:2核4G
- JVM内存大小:2G
- 系统运行时间:7天
- 期间发生的Full GC次数和耗时:500多次,200多秒
- 期间发生的Young GC次数和耗时:1万多次,500多秒
大致算下来每天会发生70多次Full GC,平均每小时3次,每次Full GC在400毫秒左右;
每天会发生1000多次Young GC,每分钟会发生1次,每次Young GC在50毫秒左右。
JVM参数设置如下:
‐Xms1536M ‐Xmx1536M ‐Xmn512M ‐Xss256K ‐XX:SurvivorRatio=6 ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M
XX:+UseParNewGC ‐XX:+UseConcMarkSweepGC ‐XX:CMSInitiatingOccupancyFraction=75 ‐XX:+UseCMSInitiatingOccupancyOnly
大家可以结合对象挪动到老年代那些规则推理下我们这个程序可能存在的一些问题
经过分析感觉可能会由于对象动态年龄判断机制导致full gc较为频繁
为了给大家看效果,我模拟了一个示例程序(见课程对应工程代码:jvm-full-gc),打印了jstat的结果如下:
jstat ‐gc 13456 2000 10000
对于对象动态年龄判断机制导致的full gc较为频繁可以先试着优化下JVM参数,把年轻代适当调大点
‐Xms1536M ‐Xmx1536M ‐Xmn1024M ‐Xss256K ‐XX:SurvivorRatio=6 ‐XX:MetaspaceSize=256M ‐XX:MaxMetaspaceSize=256M ‐XX:+UseParNewGC ‐XX:+UseConcMarkSweepGC ‐XX:CMSInitiatingOccupancyFraction=92 ‐XX:+UseCMSInitiatingOccupancyOnly
优化完发现没什么变化,full gc的次数比minor gc的次数还多了
我们可以推测下full gc比minor gc还多的原因有哪些?
1、元空间不够导致的多余full gc
2、显示调用System.gc()造成多余的full gc,这种一般线上尽量通过XX:+DisableExplicitGC参数禁用,如果加上了这个JVM启动参数,那 么代码中调用System.gc()没有任何效果
3、老年代空间分配担保机制
最快速度分析完这些我们推测的原因以及优化后,我们发现young gc和full gc依然很频繁了,而且看到有大量的对象频繁的被挪动到老年 代,这种情况我们可以借助jmap命令大概看下是什么对象
查到了有大量User对象产生,这个可能是问题所在,但不确定,还必须找到对应的代码确认,如何去找对应的代码了?
1、代码里全文搜索生成User对象的地方(适合只有少数几处地方的情况)
2、如果生成User对象的地方太多,无法定位具体代码,我们可以同时分析下占用cpu较高的线程,一般有大量对象不断产生,对应的方法 代码肯定会被频繁调用,占用的cpu必然较高 可以用上面讲过的jstack或jvisualvm来定位cpu使用较高的代码,最终定位到的代码如下:
import java.util.ArrayList; @RestController public class IndexController { @RequestMapping("/user/process") public String processUserData() throws InterruptedException { ArrayList<User> users = queryUsers(); for (User user: users) { //TODO 业务处理 System.out.println("user:" + user.toString()); } return "end"; }private ArrayList<User> queryUsers() {ArrayList<User> users = new ArrayList<>();for (int i = 0; i < 5000; i++) { users.add(new User(i,"zhuge")); } return users; }}
同时,java的代码也是需要优化的,一次查询出500M的对象出来,明显不合适,要根据之前说的各种原则尽量优化到合适的值,尽量消 除这种朝生夕死的对象导致的full gc
内存泄露到底是怎么回事
再给大家讲一种情况,一般电商架构可能会使用多级缓存架构,就是redis加上JVM级缓存,大多数同学可能为了图方便对于JVM级缓存就 简单使用一个hashmap,于是不断往里面放缓存数据,但是很少考虑这个map的容量问题,结果这个缓存map越来越大,一直占用着老 年代的很多空间,时间长了就会导致full gc非常频繁,这就是一种内存泄漏,对于一些老旧数据没有及时清理导致一直占用着宝贵的内存 资源,时间长了除了导致full gc,还有可能导致OOM。 这种情况完全可以考虑采用一些成熟的JVM级缓存框架来解决,比如ehcache等自带一些LRU数据淘汰算法的框架来作为JVM级的缓存。
JVM调优与工具命令相关推荐
- JVM调优系列--Java命令选项(参数)--大全/详解/常用
原文网址:JVM调优系列--Java命令选项(参数)--大全/详解/常用_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍Java的java命令用法,包括:常用用法.选项大全. J ...
- 关于JVM调优的工具及JVM 常见调优参数
六个命令行排查工具 我们一般使用 JDK 自带的 6 个命令行工具来排查JVM.它们分别是:jps.jstat.jinfo.jmap.jhat 和 jstack,它们都位于 JDK 的 bin 目录下 ...
- JVM 调优实战--jhat命令使用详解
jhat也是jdk内置的工具之一.主要是用来分析java堆的命令,可以将堆中的对象以html的形式显示出来,包括对象的数量,大小等等,并支持对象查询语言. 使用jmap等方法生成java的堆文件后,使 ...
- JVM 调优实战--常用命令参数及PS收集器的GC日志格式
目录 了解JVM常用命令行参数 Parallel Scavenge(PS)的GC日志格式 了解JVM常用命令行参数 JVM的命令行参数参考:https://docs.oracle.com/javase ...
- JVM从跨平台到跨专业 Ⅲ --编译期处理、类加载、JVM调优
文章目录 编译期处理 默认构造器 自动拆装箱 泛型集合取值 可变参数 foreach 循环 switch 字符串 switch 枚举 枚举类 try-with-resources 方法重写时的桥接方法 ...
- Jvm 系列(七):Jvm 调优-工具篇
工具做为图形化界面来展示更能直观的发现问题,另一方面一些耗费性能的分析(dump文件分析)一般也不会在生产直接分析,往往dump下来的文件达1G左右,人工分析效率较低,因此利用工具来分析jvm相关问题 ...
- jvm系列(四):jvm调优-命令大全(jps jstat jmap jhat jstack jinfo)
2019独角兽企业重金招聘Python工程师标准>>> 文章同步发布于github博客地址,阅读效果更佳,欢迎品尝 运用jvm自带的命令可以方便的在生产监控和打印堆栈的日志信息帮忙我 ...
- jvm系列(七):jvm调优-工具篇
16年的时候花了一些时间整理了一些关于jvm的介绍文章,到现在回顾起来还是一些还没有补充全面,其中就包括如何利用工具来监控调优前后的性能变化.工具做为图形化界面来展示更能直观的发现问题,另一方面一些耗 ...
- JVM调优:运行参数,内存模型,mat、jps、jstat、jmap、jstack、jvisualvm工具的使用
JVM调优 - 工具篇 作者:张学亮 讲解内容 了解下我们为什么要学习JVM优化 掌握jvm的运行参数以及参数的设置 掌握jvm的内存模型(堆内存) 掌握jamp命令的使用以及通过MAT工具进行分析 ...
最新文章
- Caused by: java.sql.BatchUpdateException
- postman断言测试脚本二 (对数据格式和内容匹配测试)
- linux mysql 实例详解_MySQL 多实例详解
- 透彻理解RPN: 从候选区域搜索到候选区域提取网络
- Python的reshape(-1,1)
- 私有属性和方法-伪私有属性和方法
- 反演控制 matlab,基于matlab的反演程序
- 数据缺失,如何智能修复?第一名方案源码分享
- c语言文件归档,Go语言tar归档文件的读写操作
- Linux命令详解词典
- 优化你简历的8个技巧
- 不会编程却想做APP ? 让Power Apps 来帮你
- 记一次酷狗音乐API的获取,感兴趣的可以自己封装开发自己的音乐播放器
- 第二章——Swift语言
- CPU 的工作原理以及为什么Apple Silicon M1 比 Intel i9 快?
- 解决浏览器 Microsoft Edge主页被hao123恶意篡改
- 服务器项目迁移本地,云服务器迁移本地
- hexo自定义域名以及解析
- 电脑磁盘空间莫名其妙满了
- C# Remoting的基础介绍
热门文章
- PIL.JpegImagePlugin.JpegImageFile与numpy.ndarray格式转换
- python-最后-高级技巧
- 使用Neo4j和简单分词算法实现菜品推荐系统
- 【JFreeChart】自定义蜘蛛网图生成带刻度三角雷达图 自定义文字风格 背景色
- PySpark机器学习 MLlib
- EMQ-X 消息存储到数据库的四种方法
- 电商的下半场,佰达慧兴述淘宝不再想只做一个“货架电商”
- 配置 SSH 双因素认证
- JavaDay05.练习4.体彩7位数摇奖+福彩大乐透摇奖
- 3dmax使用MAXScript调整对象的轴位置