目录
jinfo + 进程id ——> Java进程的一些相关信息
什么叫调优?
严格意思上来说:
- 根据需求进行jvm规划与预调优 (例如,我们规划每天要有100万的下单量,要用什么样的机器,要用多少内存)
- 优化进行jvm的环境(慢,卡顿)(这种情况要通过压测来定位到一个系统的瓶颈)
- 解决jvm在运行中出现的各种问题(Menmory Leak OOM)
现在有一段代码:
在银行体系或者互联网金融体系当中进行风控的模型,现在CardInfo里面是每个人的个人信息,getAllCardInfo()方法每次相当于在数据都读出100条数据,加入到任务列表里面,启动一个线程池,这个线程池它是固定时长固定频率的来执行任务的线程池,在这个线程池里面有50个线程,每隔100ms执行一个任务。如下:
package JVM.垃圾回收;
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 GC_Problem01 {
public static class CardInfo{
BigDecimal price = new BigDecimal(0.0);
String name = "tde";
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 InterruptedException {
executor.setMaximumPoolSize(50);
for (;;){
modelFit();
Thread.sleep(100);
}
}
private static void modelFit(){
List<CardInfo> taskList = getAllCardInfo();
taskList.forEach(
t-> {
executor.scheduleWithFixedDelay(() -> {
t.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;
}
}
D:\>java -Xms200M -Xmx200M -XX:+PrintGC 类名
-Xms200M最小堆大小
-Xmx200M最大堆大小
为什么都设为200M,不用扩容,防止内存抖动
-XX:+PrintGC :垃圾回收器的日志输出
当运行起来的时候,这里显示目前产生了一次GC
GC产生的一次原因是Allocation Failure 分配失败
原本我的年轻代占了 54656k 垃圾回收一次为1074k 总的堆大小为 198016k 回收的时长为 0.0069533 secs
命令
当我们敲Java的命令的时候,它会启动一次Java虚拟机
通常-开头的是标准参数 -X开头的是非标准参数
所以在敲java -X的时候它会把Java的非标参数给输出出来,真正调优用到的是-XX开头的
但是-XX开头的参数它是没有一个专门的文档给列出来
只能执行java -XX:+PrintFlagsFinal -version 打印所有参数的最终值 非常多
常用的命令跟踪Java进程有没有bug
jps ——> Java的进程显示
jps全称JVM Process Status Tool,一款查看java进程的工具。查看当前环境下运行的java服务的进程id和名称
jps
- -q:只输出进程id
- -m:输出虚拟机启动时传递给main()方法的参数
- -l:输出主类的全名,如果执行的是jar包,输出jar包的路径
- -v:输出启动虚拟机的参数
jinfo + 进程id ——> Java进程的一些相关信息
Configuration info for Java,一款用于实时查看和修改JVM参数的工具。注意,如果是修改,参数类型是manageable类型才能修改。
jinfo PID
jinfo -flag name PID 查看某个java进程的name属性的值
jinfo -flags PID 查看已经复制的JVM参数
jstat ——> Java统计信息或数据跟踪信息
jstat全称JVM Statistics Monitoring,一款用于监视虚拟机各种运行状态统计信息工具,主要显示如下信息:虚拟机进程的类装载、内存、垃圾收集、JIT编译等。
- 查看类装载信息
jstat -class PID 1000 10 //查看某个Java进程的类装载信息,每1000毫秒输出一次,共输出10次
- 查看垃圾收集信息
jstat -gc PID 1000 10
上图显示了各个区以及垃圾回收的情况,具体代表含义如下(C代表Capacity,U代表Used已使用大小)
- S0C和S1C代表Survivor区的S0和S1的大小
- S0U和S1U表示已使用空间
- EC表示Eden区大小,EU表示Eden区已使用容量
- OC表示老年代大小,OU代表老年代已使用容量
- MC表示方法区大小,MU表示方法区已使用容量
- CCSC表示压缩类空间大小,CCSU表示压缩类空间已使用大小
- YGC表示新生代GC次数,YGT表示新生代GC总耗时
- FGC表示Full GC次数,FGCT表示FULL GC总耗时
- GCT表示GC总耗时时间
jstack ——> 用来跟踪线程的
Stack Trace for Java,一款用于生成当前时刻的线程状态信息的快照工具,这个对于分析当前线程状态非常有用,比如说是否有哪个线程阻塞了,或者说是否发生了死锁等信息。如:
jstack PID
jstack 9824 会把9824里面所有的线程 (线程名称,线程编号,线程优先级,线程状态,线程的调用堆栈)
如果很多线程await在一把锁上面,这个时候可能你的程序产生了死锁
如果你的jvmCPU爆了,那么我怎么去查这个问题
这需要查询是什么样的线程在占用CPU,执行系统级命令top 它会进程当前占用的CPU是多少
想知道这个进程的某个线程占用的资源比较高,需要运行命令 top -Hp 11800 linux top命令 查看进程及相关线程信息
然后找到cpu资源大的查询它的线程信息 jstack ,找到这个线程之后需要定位这个线程有两种情况:
- 线程为VM一般是GC,垃圾回收线程,如果是GC,他会CPU会不断地增高,这时候需要开发人员去读GC的日志,看看日志里面是不是在执行GC,原因是什么。
- 业务线程,去看业务线程掉了那个方法,看看是那个方法不断地循环占用CPU资源
运行命令 top -Hp 11800
会发现在不断地FGC,输出信息,内存回收每次回收20M,回收结束还剩20M,每次只回收了6K,这里频繁FGC就说明内存里面有资源被占用并且回收不掉。
频繁FGC怎么定位?
观察每次FGC每次回收的情况是否正常,200M回收还是200M,一定是内存被占用而且还回收不掉,还有引用指向。
jmap
Memory Map for Java,一款用于生成堆转储快照即dump文件的命令
jmap -heap PID //打印出堆内存相关信息
jmap -dump:format=b,file=/usr/heap.hprof PID //生成dump文件
但是往外面导入文件依然会让jvm卡死不建议使用
jmap -dump:format=b,file=/usr/heap.hprof PID 产生堆存储文件,当怀疑这个jvm有bug的时候,用这个命令可以让整个这块内存,导出来存储到硬盘中,存成一个文件
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heap.hprof
上面常用参数可以设置,一旦发生OOM之后就会自动生成dump文件
jhat
Jvm Heap Analysis Tool,一款用于分析dump文件的工具
jhat heap.hprof
然后访问地址,http://localhost:7000/ 可以看到这款工具展示的信息比较简单。
进程号为8456, jmap -histo 8456,展示对应对象占了多少的字节
我的内存被占用了,并且回收不了对象就是这些对象造成的
VisualVM工具
All-in-one Java TroubleshootingTool,是JDK发布的一款功能强大的运行监控故障处理工具。
- 监控应用程序的CPU、GC、堆。方法区和线程信息(jstack和jstat的功能)
- dump文件以及分析(jmap和jhat的功能)
- 方法级的程序性能分析,可以找出被调用最多,运行时间最长的方法
- 离线程序快照:收集程序运行时配置、线程dump。内存dump等信息建立一个快照,并可以将快照发送给开发者进行bug反馈。
- 插件化处理,有无限扩展可能