一切福田,不離方寸,從心而覓,感無不通。

Java进阶(JVM调优)——JVM调优参数 & JDK自带工具使用 & 内存溢出和死锁问题案例 & GC垃圾回收

在这里插入图片描述

前言

JVM作为Java进阶的知识,是需要Java程序员不断深度和理解的。

本篇博客介绍JVM调优的相关知识,给出了一个demo案例,介绍了JVM调优的主要参数;介绍了jdk自带的jvm分析工具的使用;给出了一个内存溢出的调优场景,逐步分析定位问题,以及发生死锁的分析案例。

其他相关的JVM博客文章如下:

系列文章合集如下:
【合集】Java进阶——Java深入学习的笔记汇总 & 再论面向对象、数据结构和算法、JVM底层、多线程、类加载 …

引出


1.JVM调优的相关知识,给出了一个demo案例;
2.JVM调优的主要参数;
3.jdk自带的jvm分析工具的使用;
3.内存溢出的调优场景,逐步分析定位问题;
4.发生死锁的分析案例

JVM优化入门

案例demo代码

https://gitee.com/pet365/java-gc-demo

在这里插入图片描述

内存溢出

在这里插入图片描述

调用链

在这里插入图片描述

JDK1.8默认采用GC回收器为:PS + PO组合

如果我们不切换到G1回收器的情况下,如何进行参数调优!

什么是调优?

  1. 根据需求进行JVM规划&预调优
  2. JVM环境卡顿(找到系统瓶颈:压测)
  3. 解决JVM运行期间的问题(内存泄漏,内存溢出……)

调优,都必须根据业务场景来调优,不能假设,假设式的调优都是耍流氓!

JVM调优参数

调优参数:java -X & java -XX 开头的这些非标准参数!

主要是java -XX开头的参数,但是没有文档信息介绍

在这里插入图片描述

 

-XX参数主要有3种:行为参数,调优参数,调试参数

 

可以参考:https://blog.csdn.net/geejkse_seff/article/details/124288313

 

使用jdk自带的工具分析

通过DOS命令窗口,启动jar包

jconsole.exe

在这里插入图片描述

选择不安全连接

在这里插入图片描述

查看VM概要,有启动时设置的参数

在这里插入图片描述

查看控制台概览,堆内存不断增加

在这里插入图片描述

年轻代的gc回收

在这里插入图片描述

可以手动GC

在这里插入图片描述

jvisualvm.exe

另外一个工具 jvisualvm.exe

在这里插入图片描述

能够监测到死锁的产生

在这里插入图片描述

生成dump文件查看

在这里插入图片描述

控制台进行各种GC

在这里插入图片描述

垃圾回收

在这里插入图片描述

开始出现Full GC

在这里插入图片描述

此时,jvm只在回收垃圾

在这里插入图片描述

内存溢出的调优场景

在这里插入图片描述

在Linux系统上运行:

top、 jps 、jinfo、jstat 、jmap

另开一个窗口,去使用上述的命令:

内存溢出在实际的生产环境中经常会遇到,比如,不断的将数据写入到一个集合中,出现了死循环,读取超大的文件等等,都可能会造成内存溢出。如果出现了内存溢出,首先我们需要定位到发生内存溢出的环节,并且进行分析,是正常还是非正常情况,如果是正常的需求,就应该考虑加大内存的设置,如果是非正常需求,那么就要对代码进行修改,修复这个bug。首先,我们得先学会如何定位问题,然后再进行分析。

在这里插入图片描述

cpu飙升

在这里插入图片描述

top命令发现是java

在这里插入图片描述

jps 查看java进程

jps

在这里插入图片描述

jinfo 63205 查看JVM参数配置

jinfo 63205 查看参数配置

在这里插入图片描述

发现参数 -Xms200m -Xmx200M -XX:+PrintGC似乎并没有不合理的设置

jstat 查看java进程内存分配

在这里插入图片描述

  • S0C: 年轻代中第一个survivor(幸存区)的容量(字节)
  • S1C: 年轻代中第二个survivor(幸存区)的容量(字节)
  • S0U: 年轻代中第一个survivor(幸存区)目前已使用空间(字节)
  • S1U: 年轻代中第二个survivor(幸存区)目前已使用空间(字节)
  • EC: 年轻代中Eden(伊甸园)的容量(字节)
  • EU: 年轻代中Eden(伊甸园)目前已使用空间(字节)
  • OC: Old代的容量(字节)
  • OU: Od代目前已使用空间(字节)
  • MC: metaspace(元空间)的容量(字节)
  • MU: metaspace(元空间)目前己使用空间(字节)
  • YGC:从应用程序启动到采样时年轻代中gC次数
  • YGCT: 从应用程序启动到采样时年轻代中gC所用时间(S)
  • FGC:从应用程序启动到采样时old代(全gc) gc次数
  • FGCT:从应用程序启动到采样时old代(全gc) gc所用时间(s)
  • GCT:从应用程序启动到采样时gc用的总时间(s)

jstack 打印出进程内部栈的调用链信息

在这里插入图片描述

top -p 29046 -H 打印出进程内部线程的CPU占用情况

在这里插入图片描述

jmap -histo 查看进程中的类,以及类的实例个数

jmap -histo 4498 | head -20 #查看前20条信息

在这里插入图片描述

剩余的工作:去调整你的业务代码,但是jmap的缺陷在于:它在导出内存图的时候,会STW,所以需要少用!

最好在测试环境中去 复盘出 生产环境的问题;然后在测试机上去使用jmap命令!

导出快照仍旧会导致STW问题,会导致所有业务线程卡死!

所以什么时间生成堆文件呢!

-XX:+HeapDumpOnOutOfMemoryError JVM由于内存不足宕机的时候,自动生成

-XX:HeapDumpPath=/root/springbootgc.hprof 堆文件的存储位置

发生死锁的调优场景

有些时候我们需要查看下jvm中的线程执行情况,比如,发现服务器的CPU的负载突然增高了、出现了死锁、死循环等,我们该如何分析呢?由于程序是正常运行的,没有任何的输出,从日志方面也看不出什么问题,所以就需要看下jvm的内部线程的执行情况,然后再进行分析查找出原因。这个时候,就需要借助于jstack命令了,jstack的作用是将正在运行的jvm的线程情况进行快照,并且打印出来:

在这里插入图片描述

线程的状态

在这里插入图片描述

在Java中线程的状态一共被分成6种:

  • 初始态(NEW):创建一个Thread对象,但还未调用start()启动线程时,线程处于初始态。
  • 运行态(RUNNABLE):在Java中,运行态包括 就绪态 和 运行态。
    • 就绪态:该状态下的线程已经获得执行所需的所有资源,只要CPU分配执行权就能运行,所有就绪态的线程存放在就绪队列中
    • 运行态:获得CPU执行权,正在执行的线程,由于一个CPU同一时刻只能执行一条线程,因此每个CPU每个时刻只有一条运行态的线程
  • 阻塞态(BLOCKED):
    • 当一条正在执行的线程请求某一资源失败时,就会进入阻塞态。
    • 而在Java中,阻塞态专指请求锁失败时进入的状态。
    • 由一个阻塞队列存放所有阻塞态的线程。
    • 处于阻塞态的线程会不断请求资源,一旦请求成功,就会进入就绪队列,等待执行。
  • 等待态(WAITING)
    • 当前线程中调用wait、join、park函数时,当前线程就会进入等待态。
    • 也有一个等待队列存放所有等待态的线程。
    • 线程处于等待态表示它需要等待其他线程的指示才能继续运行。
    • 进入等待态的线程会释放CPU执行权,并释放资源(如:锁)
  • 超时等待态(TIMED_WAITING)
    • 当运行中的线程调用sleep(time)、wait、join、parkNanos、parkUntil时,就会进入该状态;
    • 它和等待态一样,并不是因为请求不到资源,而是主动进入,并且进入后需要其他线程唤醒;
    • 进入该状态后释放CPU执行权 和 占有的资源。
    • 与等待态的区别:到了超时时间后自动进入阻塞队列,开始竞争锁。
  • 终止态(TERMINATED)
    线程执行结束后的状态

使用jstack进行分析

在这里插入图片描述


总结

1.JVM调优的相关知识,给出了一个demo案例;
2.JVM调优的主要参数;
3.jdk自带的jvm分析工具的使用;
3.内存溢出的调优场景,逐步分析定位问题;
4.发生死锁的分析案例

 

from:https://blog.csdn.net/Pireley/article/details/134319596