JVM调优案例1—风险评控
一般是运维团队首先收到报警信息(CPU飙升 Memory占用高)
/**
* 从数据库中读取信用数据,套用模型,并把结果进行记录和传输
*/
public class T15_FullGC_Problem01 {
private static class CardInfo {
BigDecimal price = new BigDecimal(0.0);
String name = "张三";
int age = 5;
Date birthdate = new Date();
public void m() {
}
}
private static ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(50,
new ThreadPoolExecutor.DiscardOldestPolicy());
public static void main(String[] args) throws Exception {
executor.setMaximumPoolSize(50);
for (;;){
modelFit();
Thread.sleep(100);
}
}
private static void modelFit(){
List<CardInfo> taskList = getAllCardInfo();
taskList.forEach(info -> {
// do something
executor.scheduleWithFixedDelay(() -> {
//do sth with info
info.m();
}, 2, 3, TimeUnit.SECONDS);
});
}
private static List<CardInfo> getAllCardInfo(){
List<CardInfo> taskList = new ArrayList<>();
for (int i = 0; i < 100; i++) {
CardInfo ci = new CardInfo();
taskList.add(ci);
}
return taskList;
}
}
让这个程序在我的虚拟机上面跑起来
跑到后面就发现在频繁的fullGC但是FullGC回收的内存小只又小,再看我们调用的ScheduledThreadPool,我们只设置了核心线程数,最大线程数,一个拒绝策略,并没有去设置它的阻塞队列的大小,然而这个阻塞队列的最大值为Integer的MaxValue然后再放那么多的对象进去,又没有给他回收,所以就会导致频繁的FullGC,但是FullGC后它的内存并没有被回收多少。
分析CPU及内存占用情况方式
可以通过top命令查看CPU及内存占用情况:
top命令观察到问题:内存不断增长 CPU占用率居高不下
同时也可以通过top -Hp查看java进程里面的各个线程的占用:
top -Hp 观察进程中的线程,哪个线程CPU和内存占比高
再来看jstack命令,输入线程id:
通过jstack 加上java程序的进程号可以获得当前java进程里面的线程信息:
需中点关注:WAITING BLOCKED
例如:
找到持有这把锁的线程:
waiting on <0x0000000088ca3310> (a java.lang.Object)
假如有一个进程中100个线程,很多线程都在waiting on ,一定要找到是哪个线程持有这把锁
怎么找?搜索jstack dump的信息,找 ,看哪个线程持有这把锁RUNNABLE【死锁问题解决】
为什么阿里规范里规定,线程的名称(尤其是线程池)都要写有意义的名称
怎么样自定义线程池里的线程名称?(自定义ThreadFactory)
jinfo命令
jstat各种区域占用的大小(不直观)
jconsole远程连接:
在本地的jdk文件目录的bin目录下面有个jconsole
java -Djava.rmi.server.hostname=192.168.75.133 -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=11111 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false -XX:+PrintGC -Xms200M -Xmx200M T15_FullGC_Problem01
jvisual远程连接:
如上就可以看到是ScheduledThreadPoolExecutor造成了OOM,但是一般不会用这个图形化界面,因为这个服务一直在影响原来的主进程。
jprofiler(要钱)一般公司不用。
1、已经上线的系统不用图形界面用什么?(cmdline arthas)
2、图形界面到底用在什么地方?测试!测试的时候进行监控(上线前压测观察)
查找有多少个对象产生:
jmap -histo 对性能影响较小
如上图的第二种方式:由于Jmap -dump比较影响性能,可以先将当前服务器给隔离然后再通过Jmap去查看信息。
Arthas
文档参考链接:
https://github.com/alibaba/arthas/blob/master/README_CN.md
运行刚才的风险评控程序发现JVM垃圾回收器的FullGC每次都只会回收一点点。
通过Arthas来分析一下原因:
输入java -jar命令启动arthas,并输入1可以看到arhtas被挂载到42998的进程上面了
输入help就能看到athas的命令了:
arthas的JVM命令介绍:相当于jinfo,查看JVM的详细配置信息:
包含了一些JVM的基础信息
也包含了垃圾收集器算法的信息:
还有thread命令,查看线程的相关信息
查看线程状态:
输入dashboard命令类似于top命令:
还有heapdump相当于jmap导出堆信息:
对系统性能会有影响
dump文件分析
jhat命令分析heapdump的文件
如上启动了一个server:
找到instance counts for All Classes,类似于一个jmap分析的结果:
使用OQL工具查找特定对象的问题:
可以通过查看哪些对象出了问题:
arthas的反编译和热替换
jad反编译
作用:
1、动态代理生成类的问题定位
2、第三方的类(观察代码)
3、版本问题(确定自己最新提交的版本是不是被使用)
redefine热替换
编译运行程序:
此时输出的是1,然后再用arthas监控,redefine
然后再vi TT.java,直接改
然后再javac TT.java
然后再在arthas处redifine:
然后再在输入窗口那里输入a此时输出2: