虚拟机性能监控与分析处理工具

JDK命令行工具:jdk \bin 路径下,大多是jdk\lib\tools.jar类开的一层包装
1.jps:列出正在运行的虚拟机进程,显示虚拟机执行主类函数所在类的名称,以及虚拟机进程的唯一ID
如果同时启动了多个虚拟机,根基进程名称不好区分,可以通过jps显示主类的功能区分(jps -l)


2.jstat:监视各种运行状态信息,没有图形界面时,时运行期定位虚拟机性能问题的首选(类加载,垃圾收集,运行期编译状况)
jstat -class,jstat -gc,jstat -compiler
jstat -gccause:查询最近一次GC的原因


3.jinfo:实时查看和调整虚拟机各项参数(jps -v查看虚拟机启动时显示指定的参数,jinfo -flag查看系统默认参数)


4.jmap:生成堆转储快照,查询finalize执行队列,java堆和永久代详细信息,哪种收集器等
也可以用-XX:+HeapDumpOnOutOfMemoryError参数,让虚拟机在OOM时自动生成转储文件

jmap -dump:format=b,file=heap.hprof PID 生产dump文件

jmap -histo显示堆中对象统计信息,类,实例数量

jmap -histo:live pid | more:

如何监控 kvm虚拟机的网卡流量 虚拟机性能监控_垃圾收集器




5.jhat:来分析jmap生成的堆转储快照(一般不用:比较简陋,耗时耗资源)

MAT工具分析堆dump文件,在线处理网站:perfMa(分析线程dump,堆dump)

 

gcviewer.jar:本地的分析GC日志的工具, 在线分析GC日志网站:GCeasy.io


6.jstack:生成虚拟机当前时刻的线程快照:当前虚拟机内每一条线程正在执行的方法堆栈集合。用来定位线程出现长时间停顿的原因

 

 

重点:

jps 查看当前Java进程 
jinfo -flag UseG1GC PID 查看参数
jinfo -flag name=value PID 动态赋值
jinfo -flags PID 查看所有人为修改过的参数

jstack PID 线程发生问题,查看线程堆栈信息

分析堆内存dump:
jmap -dump:format=b,file=heap.hprof PID 发生OOM时查看堆信息
-XX:+HeapDumpOnOutOfMemoryError

MAT工具打开hprof文件,
点击histogram 列出各类实例的数量
leak suspects 内存泄露的可能原因

PerfMa 在线的分析堆内存dump的工具

分析GC日志:
-XX:+PrintGCDetails

看吞吐量(Throughput) 停顿时间(pauses)
gcviewer分析GC日志
GCeasy.io 在线的分析

不断选择垃圾收集器,观察这两个指标的变化

触发垃圾回收的时机:
1.Eden区或S区不够用,YONG区不够用  minorGC
2.老年代不够用 MajorGC 伴随着MinorGC
3.方法区不够用
4.System.gc()--->手动调用

G1垃圾收集器:Mixed GC:young区和部分Old区的GC
并发标记发生的前提:堆内存使用率45%以上

评价垃圾收集器的好坏:gcviewer辅助分析指标
吞吐量(Throughput)   停顿时间(最大,最小,平均)    GC次数

JVM调优:
(1)-堆不够用了?调整堆大小,看上面参数变化(吞吐量增加,GC次数减少,停顿时间增长)
(2)-(G1收集器)手动调整目标停顿时间 -MaxGCPauseMills (停顿时间少了,GC次数多了)
(3)-启动并发GC时 堆内存使用占比默认时45%  InitialingHeapOccupancyPercent=50(55,60)
(4)-JVM其他的参数  -XX:G1HeapWastePercent   ConcGCThreads
(5)-是否垃圾收集器不合适,(大内存空间使用的却是parallel)改用GC

G1官网堆调优建议:
1.不要手动设置-Xmn yong区大小和-XX:NewRatio(因为G1为了达到设置的目标停顿时间,会自动调整这个Young和old的比例)
2.设置目标停顿时间
3.参数调整

fullGC次数频繁--->调整YOUNG和Old区的比例,使得大多数在MinorGc时收集掉

CPU使用率高了,可能时GC频繁,GC的线程繁忙
CPU持续飙升排查:
(1):top--->id---->jstack 
(2):集群 分发单机器流量
(3):MQ 削峰
(4):业务层面,是否有死锁

OOM怎么排查:
dump文件 分析(MAT)

内存泄露和内存溢出OOM区别?
内存泄露指占用的空间应该被回收的,但是不能被垃圾收集,久而久之导致OOM

 

 

 

可视化工具:

1.JConsole:zai JDK/bin目录下启动:jconsole.exe:自动搜索本机运行的所有虚拟机进程。
概述页:显示虚拟机主要的运行数据概览:堆内存,线程,类等
内存页:监视收集器管理的虚拟机内存(堆,永久代)的变化趋势
线程监控:遇到线程停顿时使用:等待外部资源(数据库,网络),死循环,锁等待


2.VisualVM:多合一故障处理工具
方法级性能分析:找出被调用最多,运行时间最长的方法
生成和浏览堆转储快照
Profiler页:程序运行期间方法级CPU执行时间分析,内存分析
BTrace动态日志跟踪:动态加入原本不存在的调试代码。打印调用堆栈,参数,返回值。性能监视,定位连接泄漏,内存泄露,多线程竞争 等问题

 

阿里的:arthas:定位JAVA生产级别的问题:查看堆,线程方面的信息

 

 

 

 

 

 

 

 

调优案例:

1.高性能硬件:堆内存太大,一次Full GC耗时太长,从磁盘读文件到内存中,出现很多文档序列化的大对象,直接进入老年待。频繁Full GC


使用多个32位虚拟机建立逻辑集群,(避免64位虚拟机指针膨胀及数据类型对齐等消耗内存)
一台物理机上启动多个服务进程,分配不同端口,负载均衡。CPU敏感度较低:采用CMS收集器垃圾回收
注意:1.避免节点竞争全局资源(磁盘IO)


2.集群建同步导致内存溢出:信息传输失败重发,所有发送信息保存在内存中,网络交互频繁时 数据不断堆积。


3.堆外内存溢出:
NIO操作需要用到Direct Memory 
JNI调用本地库,使用的内存也不再堆中 不能像新生代和老年代一样发现空间不足就通知收集器回收。只能等老年代满了,Full GC时 顺便 清理 

注意:-XX:MaxDirectMemorySize调整Direct Memory大小


4.外部命令导致CPU占用率高:
Rumtime.getRuntime().exec():先克隆一个和当前虚拟机一样环境变量的进程,再用该进程执行外部命令,再推出该进程


5.服务器JVM崩溃:
异步方式调用Web服务:由于两边服务速度不等,时间久了,积累了很多Web服务没有调用完,导致在等待的线程和Socket连接很多。虚拟机 崩溃。

注意:异步调用改成 生产者/消费者模式的消息队列实现

 

 

 

 

 

 

 

 

 

 

 

tips:

java为了实现跨平台,java代码编译形成Class文件存储的是字节码ByteCode,虚拟机通过解释当时执行字节码命令。比起C/C++编译成本地二进制
很慢。所以有了JIT编译器



编译时间是指虚拟机的JIT编译器 编译热点代码的耗时。
可以使用虚拟机参数:-Xint禁止编译器工作。


发生一次垃圾收集,用户线程需跑到最近的一个安全点,挂起线程等待垃圾回收


要求虚拟机生成GC日志:-XX:+PrintGCTimeStamps(GC停顿时间)
-XX:+PrintGCDetails(GC详细信息)
-XX:+DisableExplicitGC屏蔽System.gc()

对于与用户交互频繁的应用,使用CMS收集器:-XX:+UseConcMarkSweepGC
-XX:CMSInitiatingOccupancyFraction 设置CMS老年代发生Full GC的内存使用值