----------------案例---------------
JAVA 线上故障排查完整套路,从 CPU、磁盘、内存、网络、GC 一条龙! https://mp.weixin.qq.com/s/Sk_P1tH0WFXIys67Eep0zg
------------调优工具--------------
1)jvisualvm(装visualGC+jconsole)
jvisualvm 一个基于图形化界面的、可以查看本地及远程的JAVA GUI监控工具
dk自带全能工具,分析程序死锁,(监视标签里还能导出正在监控的)内存dump、线程dump;(用它的VisualGc插件来)监控内存变化、GC变化等。还能导入生产的堆dump文件==堆快照内容(dump文件里能看到类实例对象的大小占比找出大对象)
2)jconsole,
jconsole 一个java GUI监视工具,可以以图表化的形式显示各种数据
对JVM中内存,线程和类等的监控
3)GCeasy,
一款专业分析gc日志的工具,能查内存大小分配比例,吞吐量,最大最小停顿时间,普通GC和fullGC的GC耗时时长和,查找内存泄漏
4)其他
程序运行中经常会遇到各种问题,定位问题时通常需要综合各种信息,如系统日志、堆dump文件、线程dump文件、GC日志等。通过虚拟机监控和诊断工具可以帮忙我们快速获取、分析需要的数据,进而提高问题解决速度。 本文将介绍虚拟机常用监控和问题诊断命令工具的使用方法,主要包含以下工具:
jps 显示系统中所有Hotspot虚拟机进程
jstack 显示虚拟机的线程栈快照信息
jstat收集Hotspot虚拟机各方面运行数据(堆实时内存情况--大对象占比,GC回收)
jmap用于生成虚拟机的内存快照信息(堆快照)
jinfo 显示虚拟机的配置信息(看内存各块配置大小,看GC收集器的配置)
jhat 用于对JAVA heap进行离线分析的工具(和jvisualvm类似)
Jdb 对core文件和正在运行的Java进程进行实时地调试
------------21.调优命令------按顺序来查未知问题--------
1)------- top -c // 通过查看该进程,再直接输一个大写P,会按CPU百分比倒序,找到最占cpu的进程ID1=11146
1)-------top -Hp
11146 // 可以查看该进程下各个线程的cpu使用情况,看看是否哪个线程问题明显
1)-------jinfo -flags 11146 // 查看jvm当前配置的参数,判断堆里的新老年代分配比例合理不。??
1)------- jstat -class 11146 // 命令可以查看堆内存加载类的数量,class可以换成其他变量,比如查gc次数、新老代垃圾回收统计
1)-------jmap下的一些命令 // 用于生成heap dump文件==堆快照内容,Java Virtual Machine Memory Map
1)------- jstack下的一些命令 // jstack,用于生成java虚拟机当前时刻的线程快照==堆dump文件里的内容。查找死锁
jps,JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程。
jstat,JVM statistics Monitoring是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。
jhat,JVM Heap Analysis Tool命令是与jmap搭配使用,用来分析jmap生成的dump,jhat内置了一个微型的HTTP/HTML服务器,生成dump的分析结果后,可以在浏览器中查看
df -lh //磁盘占比查看
jps -mlvv //(Java Virtual Machine Process Status Tool)
jps -mlvv //找出当前java进程号,,然后显示出内存分配及GC器配置信息、依赖jar包路径全称
ps -ef | grep java | grep pcs-core //找出所有目录的java进程号,并过滤一下带pcs-core名称的进程号,然后显示出内存分配及GC器配置信息、依赖jar包路径全称
jps -v //输出传递给JVM的参数
----------------------排查oom顺序---------------------
总结
1.如果程序内存不足或者频繁GC,很有可能存在内存泄露情况,这时候就要借助Java堆Dump查看对象的情况。(分析原因)
2.要制作堆Dump可以直接使用jvm自带的jmap命令
3.可以先使用jmap -heap命令查看堆的使用情况,看一下各个堆空间的占比情况。
4.使用jmap -histo:[live]查看当前堆内存中的对象的情况。如果有大量对象在持续被引用,并没有被释放掉,那就产生了内存泄露,就要结合代码,把不用的对象释放掉。
5.也可以使用 jmap -dump:format=b,file=<fileName>命令将堆信息保存到一个文件中,再借助jhat命令或jvisualvm查看详细内容
6.在内存出现泄露、溢出或者其它前提条件下,建议多dump几次内存,做对比,把内存文件进行编号归档,便于后续内存整理分析。
7.在用cms gc的情况下,执行jmap -heap有些时候会导致进程变T,因此强烈建议别执行这个命令,如果想获取内存目前每个区域的使用状况,可通过jstat -gc(实时查看)或jstat -gccapacity来拿到。
------------------死锁查找有哪些方面法-----------------
一、让运维生成线程快照,用jvisualvm分析程序死锁
二、用jstack工具和jvm自身支持的命令,直接命令行查出来:
jstack找出占用cpu最高的堆栈信息
1,使用命令top -p <pid> ,显示你的java进程的内存情况,pid是你的java进程号,比如4977
2,按H,获取每个线程的内存情况
3,找到内存和cpu占用最高的线程tid,比如4977
4,转为十六进制得到 0x1371 ,此为线程id的十六进制表示
5,执行 jstack 4977|grep -A 10 1371,得到线程堆栈信息中1371这个线程所在行的后面10行
6,查看对应的堆栈信息找出可能存在问题的代码
------------------GC调优步骤------通过gc日志的方法------------
打印GC日志
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:./gc.log
Tomcat则直接加在JAVA_OPTS变量里
分析日志得到关键性指标
分析GC原因,调优JVM参数
1、Parallel Scavenge收集器(默认)
分析parallel-gc.log
调优:
第一次调优,设置Metaspace大小:增大元空间大小-XX:MetaspaceSize=64M -XX:MaxMetaspaceSize=64M
第二次调优,增大年轻代动态扩容增量,默认是20(%),可以减少young gc:-XX:YoungGenerationSizeIncrement=30
比较下几次调优效果:
吞吐量 最大停顿 平均停顿 Young gc Full gc
98.356% 120 ms 19 ms 19 2
99.252% 20 ms 10 ms 16 0
99.24% 17
2、配置CMS收集器
-XX:+UseConcMarkSweepGC
分析cms-gc.log
3、配置G1收集器
-XX:+UseG1GC
分析g1-gc.log
young GC:[GC pause (G1 Evacuation Pause) (young)
initial-mark:[GC pause (Metadata GC Threshold) (young) (initial-mark) (参数:InitiatingHeapOccupancyPercent)
mixed GC:[GC pause (G1 Evacuation Pause) (mixed) (参数:G1HeapWastePercent)
full GC:[Full GC (Allocation Failure) (无可用region)
(G1内部,前面提到的混合GC是非常重要的释放内存机制,它避免了G1出现Region没有可用的情况,否则就会触发Full GC事件。
CMS、Parallel、Serial GC都需要通过Full GC去压缩老年代并在这个过程中扫描整个老年代。G1的Full GC算法和Serial GC收集器完全一致。当一个Full GC发生时,整个Java堆执行一个完整的压缩,这样确保了最大的空余内存可用。G1的Full GC是一个单线程,它可能引起一个长时间的停顿时间,G1的设计目标是减少Full GC,满足应用性能目标。)
查看发生MixedGC的阈值:jinfo -flag InitiatingHeapOccupancyPercent 进程id
调优:
第一次调优,设置Metaspace大小:增大元空间大小-XX:MetaspaceSize=64M -XX:MaxMetaspaceSize=64M
第二次调优,添加吞吐量和停顿时间参数:-XX:GCTimeRatio=80 -XX:MaxGCPauseMillis=100
分析工具:gceasy,GCViewer
--------------------------常见题分析--------------------------
08-JVM整体结构与垃圾回收算法介绍
1、(K73)(a+b)*10,10是存在哪里的?是常量池么?,如果是常量池,在进行运算的时候,是通过指针来找到的吧,这样咱们的架构图是不是少了一部分啊?
10是在常量池,因为常量池在jdk1.8以后已经移到元空间了,所以画运行时数据区不好一起画出来,PPT上有关于常量池的存储变化
2、(L81)
动态链接 和 引用 有什么区别?
动态链接指对类信息的引用在运行过程中才能确定,引用是指对象级别,一个类信息级别,一个队对象级别,动态链接要彻底理解还需要了解下编译原理等知识,可查下相关资料
3、(F43)堆到底装对象的什么部分(只是对象的引用吗?)?方法区里放的是对象的字节码,栈里放的是线程所有方法执行的代码,感觉堆里没有什么东西放了啊?
对象里的数据哈,成员变量之类的啊,栈里放到是方法的局部变量
4、在服务器里,我们是怎么启动jvm的(一般我们就安装jdk包,配置了一下)
最终还是通过java命令哈,服务器启动也是通过java命令运行jar包里的一个入口类启动
5、tomcat我们安装时,压根就没有配置jdk的路径,是怎么和jdk关联上的(也就是tomcat里的东西怎么,什么时候放到jvm中去的?)
需要配置JAVA_HOME的,你不配置试试能启动不,tomcat启动时会去环境变量里找JAVA_HOME
09-类加载器深入解析
1、(M12)双亲委派机制能够保证核心类安全,那其他的非核心类呢?
你公司自己开发的类没办法保证,JVM只保证它自己的核心类不被破坏
2、(F43)怎么把jstack查出的线程单独杀掉(一般根据nid找出的pid杀掉会连带杀掉进程)?
你这找出的pid是进程id吧,还真没单独kill过某一个线程。。貌似有点困难
3、(K73)内存泄漏通过什么命令来查呢?
还是要用jmap的内存快照分析
10-GC日志格式详解
1、(M49)实际生产OOM处理处理思路是什么?
答:先重启让程序运行,然后根据溢出生成的dump文件分析原因,解决可能存在的bug
2、(H36) java四种引用类型跟垃圾回收的关系,平时只用考虑强引用吗?
答:我们这里说的引用都是指的强引用,其他几种引用用得不多吧
3、(C81)我们用的 parallel gc, 在服务器没有用户访问的时候,堆内存会慢慢增长,直到内存使用率达到95%以上甚至到了99%,触发了full fc才会降下来,然后继续慢慢增长,如此循环。而有用户请求时反而不会有这种情况,内存增长的速度稍快一些,但会频繁回收。
答:把dump拿出来分析下看是什么对象一直在增长,然后找对应的代码分析
4、问题:对象多大字节会放H区
L50
答:超过region块一半以上空间的对象有可能会被放入H区
5、java堆内存的模型,是在启动jvm参数 设置哪个垃圾回收器定的么?老师讲到G1垃圾回收器的时候讲到说 java堆不是
不要考虑 yong 区 eden from to 的概念了,根据这个理念我觉得应该是所以确认一下。
I41
答:是启动的时候指定垃圾回收器,不指定的话JDK会根据版本默认一个回收器
是说不在想其它收集器那样考虑young和old区了,但是每个region还是有区别的,仔细看下我视频里讲的region分类
6、cms是1.8默认老年代的收集器,parallel是1.8默认新生代的收集器对吗?各个版本的jdk中新老年代,默认收集器,从1.6开始。
I66
答:我课上说了jdk1.8默认的是parallel收集器,它还有一个老年代版本,年轻代和老年代默认都是用parallel。Jdk9是G1,jdk1.8前版本默认收集器自己去查下文档吧
--11-GC调优实战--
1、(M72)
线上单机再跑的,那是需要重启启动,配上参数,来打印日志呀?
重启配置上可以,如果不想重启通过jinfo应该也是可以动态修改一些jvm参数的,可以查下相关资料
2、 线上再跑的项目如果需要调整元空间大小,也需要重新启动项目吗?
可以看下jinfo这个命令,可以动态修改一些jvm参数的,不确定是否一定能修改元空间大小,可以查下相关资料
3、(B27)
GC调优,不应该是直接根据启动日志就能做到调优吧?我觉得更多的是根据系统长时间运行,得到的JVM的GC日志,才能有一个JVM GC整体的概况,才能更好做到调优。
是的,要根据长时间的运行日志来分析,我课上只是拿启动日志举例
4、(M51)
gc频繁和gc时间长 这两种调优的基本思路是什么?
gc频繁可能是分配的空间较少,可以结合日志分析看是否需要调大一点,我最后一节课上有讲
gc时间长就需要结合日志具体分析了,不好说具体原因,有可能是内存分配过大,或者程序有bug导致垃圾对象过多
5、jvm堆的结构是不是由收集器决定的 ?例如g1 就会跟成多个regin区域管理。
是的,就是JVM内部根据不同的收集器的不同实现