一、调优和监控概述
1、调优目的
(1)防止出现OOM
(2)解决OOM
(3)减少Full GC出现的频率
2、监控
(1)运行日志
(2)异常堆栈
(3)GC日志
(4)线程快照
(5)堆转储快照
二、内存泄露--导致OOM
1、内存泄露
严格上,对象不会被程序用到了,但是GC又不能回收他们
宽泛上,不太好的实践导致对象的生命周期变得很长,甚至导致OOM,也可叫内存泄露
2、内存泄露的8个情况
(1)静态集合类--存放局部变量
存放在静态集合类中的obj局部对象,虽然在方法执行后不使用了,但是由于在静态list集合中,不能被释放
(2)单例模式
(3)内部类持有外部类
(4)各种资源连接问题,如果在finally中没有手动close()
(5)变量不合理的作用域,定义范围>其使用范围,如 局部变量声明成成员变量
解决:最后令其为null
(6)改变对象的哈希值(哈希地址),导致删除失败
(7)缓存泄露---解决弱引用代替强引用
(8)监听器和回调
三、性能监控
1、命令行监控程序(cmd)
jps 查看正在运行的java进程
jstat 查看JVM统计信息
jinfo 实时查看和修改JVM配置参数
jmap 导出内存映像文件、内存使用情况
jhat JDK自带堆分析工具
jstack 打印JVM中线程快照
jstated 远程主机信息收集
2、jstat---监控GC
(1)基本语法
jstat -option -t -h interval count
- option的值常取:
-class 查看类加载相关
-gc 查看显示GC相关堆信息
- -t 程序开始运行时间,启动的时间点(时间戳)
- -h 在周期性数据输出时,输出多少行数据后输出一个表头信息
- interval 设置搁多少秒打印信息
- count 打印多少条
(2)实例1:实时查看gc相关情况
- 获取当前程序的进程号
jps
得13252 GCTest---进程号为13252
- 每隔1s打印一次该进程的gc信息,一共打印10次
jstat -gc 13252 1000 10
jstat -gc 进程号 每隔多少毫秒打印信息 打印多少条
(3)实例2: 查看gc占总运行时间的比例
jstat -gc -t 13252 1000 10
Timestanp---时间戳,程序开始运行时间
GCT---GC垃圾回收时间
GC占时间比例=GC时间增量/运行时间增量=(GCT1-GCT2)/(t1-t2)
3、jinfo---实时查看和修改JVM参数
(1)查看
- 是否使用了某GC + 使用了,-没使用
jinfo -flag UseParallelGC 3540
结果:-XX:+ UseParallelGC 使用了
- 某个值
jinfo -flag MaxHeapSize 3540
(2)修改--两查看,中间修改
- Boolean类型
jinfo -flag PrintGCDetails 3540 //查看
-XX:- PrintGCDetails //结果
jinfo -flag +PrintGCDetails 3540 //修改
jinfo -flag PrintGCDetails 3540 //再查看
-XX:+PrintGCDetails //结果
- 非Boolean类型
jinfo -flag MaxHeapFreeRatio 3540 //查看
-XX: MaxHeapFreeRatio=100 //结果
jinfo -flag MaxHeapFreeRatio =90 3540
jinfo -flag MaxHeapFreeRatio 3540 //再查看
-XX: MaxHeapFreeRatio=90 //结果
四、性能调优
1、调优大方向
- 合理编写代码
- 充分并合理的使用硬件资源
- 合理地进行JVM调优
2、性能优化步骤
- 性能监控:发现问题:异常之类的
- 性能分析:什么原因导致的--GC日志
- 性能调优:解决问题,加内存、调代码、加机器、合理设置线程池线程数量、使用中间件提高效率
目的:减少GC出现频率,FullGC出现次数,保证吞吐量情况下,STW时间尽量少
3、具体步骤
(1)性能监控--发现问题
- GC频繁
- cpu load过高
- OOM
- 内存泄漏
- 死锁
- 程序响应时间较长
(2)性能分析--排查问题
- 打印GC日志--通过GCviewer或http://gceasy.io分析日志信息
- 运用命令行工具:jstack、jmap,jinfo
- dump出堆文件,使用内存分析工具分析文件
- 使用阿里Arthas或jconsole,JVisualVM实时查看JVM状态
- jstack查看堆栈信息
(3) 性能调优--解决问题
- 适当增加内存,选择合适的垃圾回收器
- 优化代码,控制内存使用
- 增加机器,分散节点压力
- 合理设置线程池线程数
- 使用中间件提高程序效率,如缓存、消息队列等
[注]针对G1 GC调优详见