死磕Java虚拟机-性能调优实战篇
Posted Java架构师进阶手册
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了死磕Java虚拟机-性能调优实战篇相关的知识,希望对你有一定的参考价值。
Java命令分为如下三种
1. 以java - 开头:标准参数
2. 以java -X 开头:非标参数
3. 以java -XX 开头:性能调优主要用这个开头的参数,但是无法找到相关参数的帮助文档,下面我教大家几个常用的命令
-XX:+UseSerialGC = Serial New (DefNew) + Serial Old
小型程序。默认情况下不会是这种选项,HotSpot会根据计算及配置和 JDK版本自动选择收集器
-XX:+UseParNewGC = ParNew + SerialOld
这个组合已经很少用(在某些版本中已经废弃)
https://stackoverflow.com/questions/34962257/why-remove-support-for-parnewserialold-anddefnewcms-in-the-future
-XX:+UseConc(urrent)MarkSweepGC = ParNew + CMS + Serial Old
-XX:+UseParallelGC = Parallel Scavenge + Parallel Old (1.8默认) 【PS + SerialOld】
-XX:+UseParallelOldGC = Parallel Scavenge + Parallel Old
-XX:+UseG1GC = G1
Linux中没找到默认GC的查看方法,而windows中会打印UseParallelGC
java -XX:+PrintCommandLineFlags -version
通过GC的日志来分辨
Linux下1.8版本默认的垃圾回收器到底是什么?
1.8.0_181 默认(看不出来)Copy MarkCompact
1.8.0_222 默认 PS + PO
java -XX:+PrintFlagsFinal 会打印所有的JVM参数
4. 小案例如下:
package com.fengyaof.jvm.sikejvm;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class FullGC_Problem01 {
private static class CardInfo {
BigDecimal price = new BigDecimal(0.0);
String name = "张三";
int age = 5;
Date birthday = new Date();
public void m() {
}
}
private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(50,
new ThreadPoolExecutor.DiscardPolicy());
public static void main(String[] args) throws InterruptedException {
executor.setMaximumPoolSize(50);
for (; ; ) {
modelFit();
Thread.sleep(100);
}
}
private static void modelFit() {
List<CardInfo> taskList = getAllCardInfo();
taskList.forEach(info -> {
executor.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
info.m();
}
}, 2, 3, TimeUnit.SECONDS);
});
}
private static List<CardInfo> getAllCardInfo() {
List<CardInfo> taskList = new ArrayList<>();
for (int i = 0; i < 100; i++) {
CardInfo info = new CardInfo();
taskList.add(info);
}
return taskList;
}
}
我们在Linux上面用这个命令去运行:
java -Xms100M -Xmx100M -XX:+PrintGC com.fengyaof.jvm.sikejvm.FullGC_Problem01
命令运行如下: 我们可以分析出程序运行到一定的时候,Full GC每次回收的内存是2k,非常少。
我们看看top运行的内存变化:CPU上升的很高,内存消耗百分比(MEM)没有明显变化说明垃圾基本没有回收。
那么我们如何定位问题:
1) 先使用下jps 查看进程号
2) 打印进程号的信息:jinfo 1471
3) 使用命令 jstat -gc 1471 1000 (1471代表进程号,1000代表刷新频率)
4) 把进程里面所有的线程列举出来 jstack 1471
这个命令可以检查死锁:
5) jmap -histo 1697 | head -20
这个命令可以把类型有多少个对象找出来,这个命令线上不能用,会暂停服务
面试经常会问的问题:CPU飙高,内存飙高,内存泄漏,如何排查?其实arthas一个工具就可以搞定
5. 我们用arthas如何进行定位?
arthas启动完成后如下图:
arthas常用命令讲解:
1) dashboard 线程飙高怎么排查,可以使用这个命令
2) jvm 查看一些基本的信息
3) thread 查看线程的占用情况。
thread中有很好用的命令:找到死锁
thread -b 可以找到死锁
4) 例如微服务里面如何查看哪个服务调用占用的内存多,可是使用下面的命令:
1. 先查询某个类,使用模糊查询:sc *com.fengyaof*
2. 查询某个类里面的方法:
sm com.fengyaof.jvm.sikejvm.FullGC_Problem01
3. 例如我们对类中某个方法有怀疑,我们可以进行跟踪,使用trace 命令
下面,我教几个arthas重要的命令。
1) heapdump /root/temp.hprof 把堆导出来做分析
在实际生产过程中,不能使用,服务器会产生暂停。
我们用java自带的工具jvisualvm,把这个堆文件分析一下,如图:
2) jad 反编译
jad com.fengyaof.jvm.sikejvm.FullGC_Problem01
这个命令很好用,在线可以反编译看看代码是不是最新的。
3) 下面有个场景:我发现我们线上环境的某个代码不是最新的,我们该怎么快速替换这个文件呢,不能重启服务。
使用redefine命令,救急使用
我们总结一下:
CPU飙高:jstack,arthas中的thread可以揪出哪个线程飙高,可以GC线程,也可能是业务线程。
内存飙高:jmap,查看类中有多少个对象,或者是dump文件查看。
GC设定日志参数:
-Xloggc:/path/gc.log
-XX:+UseGCLogFileRotation
-XX:NumberOfGClogFiles=5
-XX:GCLogFileSize=20M
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintGCCause
设置OOM的堆存储文件:
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=C:/temp/oom.hprof
以上是关于死磕Java虚拟机-性能调优实战篇的主要内容,如果未能解决你的问题,请参考以下文章
书籍推荐:《实战Java虚拟机——JVM故障诊断与性能优化》
书籍推荐:《实战Java虚拟机——JVM故障诊断与性能优化》下载