FGC频繁导致CPU 飙升定位及JVM配置优化总结

简介: FGC频繁导致CPU 飙升定位及JVM配置优化总结

本文为博主原创,未经允许不得转载:

目录:

  1. 定位消耗cpu 的服务进程和线程

  2. 定位FGC 的原因

  3. 定位jvm 参数是否导致FGC

  4. 调试最优解的 jvm 配置


  描述:项目中存在一个后台服务,该后台服务主要用来执行定时任务与kafka 中间件消息的消费。在压测环境上部署时,观察到 cpu 的使用率 异常,竟然达到了 600%, 所以记录下该问题的定位和解决过程,以帮助更多的伙伴。

1. 定位消耗cpu 的服务进程和线程

  使用top 命令查看 服务器的cpu使用情况

top

  获取 top 中cpu 占用率最高的进程的pid ,通过 top -H -P pid 获取该进程对应所有线程的使用情况

top -H -p pid

  通过上面命令得到使用cpu 最高的线程号 threadId ,将线程号通过命令转换为十六进制:

printf "%x\n" threadId

  通过以上命令获取到jvm中对应的 nid , 通过 jstack 查看该 threadId 线程的堆栈信息:

jstack -l pid| grep -10 nid

   通过以上命令判断该线程 执行任务的内容,从而推断导致cpu飙升的原因。

       项目中碰到导致cpu飙升的原因是 存在较多的 FGC 线程,从而怀疑 是 项目内部不断FGC 导致CPU飙升,从而监控项目的FGC 频率

2. 定位FGC 的原因

  通过 jstat 命令查看 FGC 的频率。

jstat  -gc   pid  3000

  发现 FGC 每隔三秒要进行9次左右的FGC垃圾回收。由于FGC 会导致STW (stop the world)现象,及服务不可用。

  需要定位 jvm 内存中的堆栈内容与线程。通过 Visualm 远程监控服务的jvm 性能,jvisualm 使用可参考这篇文章 (https://www.cnblogs.com/zjdxr-up/p/14916455.html),通过 jvisualm 查看服务当前存在的线程和堆内容。通过jvisualm 将堆内容与线程进行dump 之后,发现并未存在异常的内容。且 定时任务与kafka 都是开源的成熟框架,应该不会是导致频繁FGC 的主要原因。

  所以怀疑可能 服务的 jvm 参数配置存在问题,因为如果 jvm 参数设置不合理,当老年代的内存达到一定比例,则会进行FGC。下一步定位 jvm 的参数是否是主要原因。

3. 定位jvm 参数是否导致FGC

  由于我们的服务启动都会设置 最大堆内存和初始化堆内存等参数,所以需要调整 不同jvm 参数 时,服务内部的FGC 情况。

  以下为我们服务设置的 JVM 相关参数

-Xmn512m -Xms512m -Xmx2048m -XX:NewSize=512M -XX:MaxNewSize=512M -XX:-UseAdaptiveSizePlicy 
-XX:ParallelGCThreads=16 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:MaxTenuringThreshold=15

  为了形成做对比,采取 java -jar 的方式启动服务,不手动设置jvm相关配置,使用 JVM 默认的配置,进行观察是否有变化。

  通过 java -jar 方式启动,使用默认配置之后,再采用 top 观察cpu 使用 与 jstat 观察 FGC 频率,发现 cpu 的使用率降了下来,恢复了正常状态。

4. 调试最优解的 jvm 配置

  获取java -jar 服务启动的进程, 再使用 jinfo 命令 查看JVM 默认的配置,并修改以上jvm 的配置。我们服务器内存均为 32G,默认最大堆内存为 服务器内存的四分之一,即最大堆内存为 8G 。其余参数可根据最大堆内存进行推算出来,通常初始化内存与最大堆内存使用相同的配置。整个堆大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。-Xmn 此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。年轻代大小 为 3G; 修改后的 jvm 配置参数如下:

-Xmn3072m -Xms8192m -Xmx8192m -XX:NewSize=3072M -XX:MaxNewSize=3072M -XX:-UseAdaptiveSizePlicy 
-XX:ParallelGCThreads=16 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:MaxTenuringThreshold=15

  补充:为了调试出相对比较好的jvm配置,将最大堆内存进行了多个配置对比,即从最大堆配置的值依次递增和递减 512M 之后,观察性能,发现默认配置依然最优解,所以才用默认配置作为服务启动的jvm配置

 

标签: JVM

目录
相关文章
|
20天前
|
Java 编译器 Linux
JVM/编译器/CPU,究竟谁是卧底?一个曾经困扰我一个月的 bug
任何复杂的系统都可能因为一个小小的疏漏而无法运转,本文记录了一个困扰作者一个月的 bug 最终拨云见日的过程。
|
27天前
|
SQL 监控 关系型数据库
MySQL优化: CPU高 处理脚本 pt-kill脚本
MySQL优化: CPU高 处理脚本 pt-kill脚本
|
19天前
|
监控 Java Linux
CPU被打满/CPU 100%:高效诊断与优化策略
【8月更文挑战第28天】在日常的工作与学习中,遇到CPU使用率飙升至100%的情况时,往往意味着系统性能受到严重影响,甚至可能导致程序响应缓慢或系统崩溃。本文将围绕这一主题,分享一系列高效诊断与优化CPU使用的技术干货,帮助大家快速定位问题并恢复系统性能。
30 1
|
2月前
|
缓存 Prometheus 监控
Java面试题:如何监控和优化JVM的内存使用?详细讲解内存调优的几种方法
Java面试题:如何监控和优化JVM的内存使用?详细讲解内存调优的几种方法
69 3
|
2月前
|
Java
手把手教你java CPU飙升300%如何优化
手把手教你java CPU飙升300%如何优化
42 0
|
28天前
|
Java Docker 索引
记录一次索引未建立、继而引发一系列的问题、包含索引创建失败、虚拟机中JVM虚拟机内存满的情况
这篇文章记录了作者在分布式微服务项目中遇到的一系列问题,起因是商品服务检索接口测试失败,原因是Elasticsearch索引未找到。文章详细描述了解决过程中遇到的几个关键问题:分词器的安装、Elasticsearch内存溢出的处理,以及最终成功创建`gulimall_product`索引的步骤。作者还分享了使用Postman测试接口的经历,并强调了问题解决过程中遇到的挑战和所花费的时间。
|
27天前
|
存储 算法 Oracle
不好意思!耽误你的十分钟,JVM内存布局还给你
先赞后看,南哥助你Java进阶一大半在2006年加州旧金山的JavaOne大会上,一个由顶级Java开发者组成的周年性研讨会,公司突然宣布将开放Java的源代码。于是,下一年顶级项目OpenJDK诞生。Java生态发展被打开了新的大门,Java 7的G1垃圾回收器、Java 8的Lambda表达式和流API…大家好,我是南哥。一个Java学习与进阶的领路人,相信对你通关面试、拿下Offer进入心心念念的公司有所帮助。
不好意思!耽误你的十分钟,JVM内存布局还给你
|
1月前
|
存储 算法 Java
JVM自动内存管理之垃圾收集算法
文章概述了JVM内存管理和垃圾收集的基本概念,提供一个关于JVM内存管理和垃圾收集的基础理解框架。
JVM自动内存管理之垃圾收集算法
|
1月前
|
存储 Java 程序员
JVM自动内存管理之运行时内存区
这篇文章详细解释了JVM运行时数据区的各个组成部分及其作用,有助于理解Java程序运行时的内存布局和管理机制。
JVM自动内存管理之运行时内存区
|
1月前
|
存储 安全 Java
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程,JDK、JRE、JVM关系;程序计数器,堆,虚拟机栈,堆栈的区别是什么,方法区,直接内存
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程是什么,JDK、JRE、JVM的联系与区别;什么是程序计数器,堆,虚拟机栈,栈内存溢出,堆栈的区别是什么,方法区,直接内存
JVM常见面试题(二):JVM是什么、由哪些部分组成、运行流程,JDK、JRE、JVM关系;程序计数器,堆,虚拟机栈,堆栈的区别是什么,方法区,直接内存