1. JVM常用命令行
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html
- java -XX:+PrintCommandLineFlags HelloGC
——执行HelloGC.java同时打印出堆内存分配情况以及压缩指针启用情况;
-XX:InitialHeapSize=199014080
-XX:MaxHeapSize=3184225280
-XX:+PrintCommandLineFlags
-XX:+UseCompressedClassPointers
-XX:+UseCompressedOops
-XX:-UseLargePagesIndividualAllocation
-XX:+UseParallelGC
- -Xmn10M -Xms40M -Xmx60M -XX:+PrintCommandLineFlags -XX:+PrintGC
——设置堆内存大小并打印GC日志(一般将Xms和Xmx设为一样,避免JVM内存大小来回缩放,消耗CPU资源,打印详细的GC日志:PrintGCDetails PrintGCTimeStamps PrintGCCauses)
-XX:InitialHeapSize=41943040
-XX:MaxHeapSize=62914560
-XX:MaxNewSize=10485760
-XX:NewSize=10485760
-XX:+PrintCommandLineFlags
-XX:+PrintGC
-XX:+UseCompressedClassPointers
-XX:+UseCompressedOops
-XX:-UseLargePagesIndividualAllocation
-XX:+UseParallelGC
Hello GC
[GC (Allocation Failure) – 55300K->55308K(60416K), 0.6399754 secs] // YGC前后内存大小
[Full GC (Ergonomics) 55308K->53974K(60416K), 0.0094122 secs] // FGC
[GC (Allocation Failure) – 53974K->53974K(60416K), 0.0172811 secs]
[Full GC (Allocation Failure) 53974K->53956K(60416K), 0.0084522 secs]
-
java -XX:+UseConcMarkSweepGC -XX:+PrintCommandLineFlags -XX:+PrintGC HelloGC
——使用CMS垃圾回收,并打印GC日志 -
java -XX:+PrintFlagsFinal | grep xxx
—— 查找包含关键字xxx的JVM指令有哪些
- -XX:+PrintGCDetails
—— GC日志详细分析
ps:堆的total内存为一个Eden + 一个Survivor(每次只用一个S)
2. 调优相关概念
调优的两个trade-off目标(项目需要哪个指标优先)
- 吞吐量:用户代码执行时间 / (用户代码执行时间 + 垃圾回收时间)
- 响应时间:STW越短,响应时间越好
吞吐量优先:PS + PO(多线程回收,大大减少GC时间)
响应时间优先:G1
3. 调优的三大方面
- 1) 按项目需求规划JVM配置,预规划(需要达到什么量级的并发,需要什么软硬件配置)
- 2) 优化JVM运行环境(系统存在运行慢,卡顿现象)
- 3) 解决JVM运行过程中出现的各类问题(定位OOM,GC参数调整等)
预规划步骤
1) 根据业务场景选择优先考虑吞吐量还是响应时间(一般考虑某个尖峰时刻的并发量来配置服务器性能:每秒业务需要多大内存以及需要在多少响应时间)
2) 选择合适的GC组合
3) 计算所需内存
4) 配置CPU(压测使得满足需求的响应时间)
5) 设定触发GC的年代大小与转化为老年代的年龄阈值
6) 设置合理的日志参数(起码要多个日志文件写入/清空,循环使用,防止单个日志文件占用大量磁盘空间,难以定位出错的日志记录行)
7) 观察日志情况来优化JVM运行环境或者解决报的各类异常
运行环境优化
1) 服务器内存小频繁GC导致卡顿,扩大服务器内存反而响应变慢?—— 内存变大,整体进行FGC的时间变长。(选择合理的GC组合)
2) (高频面试考点)CPU经常100 %怎么办?——说明有线程一直在运行
- 找出占用CPU高的进程(top)
- 找出进程中占用CPU高的线程(top -Hp)
- 导出线程的栈(jstack)
- 在栈中查找那个方法的栈帧消耗CPU高(jstack)
3) 系统内存飚高怎么排查——堆内存有问题
- 导出堆内存(jmap)
- 分析堆内存(分析工具:jhat、jprofiler……)
4) 监控JVM——jstat、arthas、jprofiler
解决程序运行的问题
-
定位哪个线程哪个类出现了运行问题——用非图形界面指令行命令:arthas(图形界面会影响服务在线运行效率,只用于测试环节)
-
定位哪个类造成的OOM——jmap查询每个类产生的实例个数,找到实例个数特别多的类;(jmap在服务器内存很大时不能用,导致服务宕机)
-
对定位到的使用以上类的代码进行错误排查;
4. arthas调优(没有提供jmap的功能,其他JDK自带的调优指令都有)
常用命令:
1) jvm——观察jvm的一些参数配置
[arthas@18002]$ jvm
2) thread + 线程id()——观察指定线程的运行情况
[arthas@18002]$ thread 1
"main" Id=1 TIMED_WAITING
at java.lang.Thread.sleep(Native Method)
at T15_FullGC_Problem01.main(T15_FullGC_Problem01.java:32)
3)dashboard == top——也就是windows的任务管理器
4)heapdump /root/test.hprof ——导出堆文件(影响性能,一般线上不用)
jhat -J-mx512M test.hprof——分析堆文件
192.168.xx.xx:7000地址远程访问分析结果报告(或者使用jvisualvm把dump下载到本地进行分析)
5)jad反编译 + redefine热替换——在线确认版本号,替换新的版本(基于classLoader里的redifine方法在不停止服务的情况下更新class文件内容)