纯干货:大对象导致FullGC频繁的原因及实践思路

2024-01-31 22:20

本文主要是介绍纯干货:大对象导致FullGC频繁的原因及实践思路,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

今天在检查线上环境的时候,发现了在2分钟内出现了2次FullGC。
虽然对线上功能影响不是很大,但还是想一探究竟。

线上监控得到的信息:
CAT监控
可以看到从短时间内有了2次GC,从13次直接飙到15次。

然后看了下老年代的堆情况:
在这里插入图片描述
可以看到这两次分别从620M直接下降到了400M然后又下降到了200M的样子。

脑海中的直觉应该是出现了大对象的感觉,因为老年代的堆是650M。达到620M触发GC,可能是堆空间不足,对象分配不进去,触发了1次GC,清理了200M,这个没什么问题,但是同一时刻又触发了一次GC,又清理了一遍,这个就是有问题了。

但是这个不是什么内存溢出啊啥的,dump不到大对象呀。事故现场已经被清理完了这可咋整喔 。

这个时候我在想,要是Full GC之前能够得到hprof文件就好了。

但其实JVM早就提供了这些参数了。

开启GC参数

# 1. 查看可实时配置的GC参数
java -XX:+PrintFlagsFinal -version | grep manageable
# 2. 查看服务进程编号
jps
# 3. 在full gc前开启dump文件 +表示开启 -表示关闭。 18881 代表应用进程编号
jinfo -flag +HeapDumpBeforeFullGC 18881
jinfo -flag HeapDumpPath=/elab/spring-boot/logs/dump_file 18881
# 查看配置是否生效
jinfo -flag HeapDumpPath 18881# 查看当前应用的jvm配置
jinfo -flags 18881

通过第一个命令可以不重启应用实时开启的参数:

java -XX:+PrintFlagsFinal -version | grep manageableintx CMSAbortablePrecleanWaitMillis            = 100                                 {manageable}intx CMSTriggerInterval                        = -1                                  {manageable}intx CMSWaitDuration                           = 2000                                {manageable}bool HeapDumpAfterFullGC                       = false                               {manageable}bool HeapDumpBeforeFullGC                      = false                               {manageable}bool HeapDumpOnOutOfMemoryError                = false                               {manageable}ccstr HeapDumpPath                              =                                     {manageable}uintx MaxHeapFreeRatio                          = 100                                 {manageable}uintx MinHeapFreeRatio                          = 0                                   {manageable}bool PrintClassHistogram                       = false                               {manageable}bool PrintClassHistogramAfterFullGC            = false                               {manageable}bool PrintClassHistogramBeforeFullGC           = false                               {manageable}bool PrintConcurrentLocks                      = false                               {manageable}bool PrintGC                                   = false                               {manageable}bool PrintGCDateStamps                         = false                               {manageable}bool PrintGCDetails                            = false                               {manageable}bool PrintGCID                                 = false                               {manageable}bool PrintGCTimeStamps                         = false                               {manageable}

这里我们关注其中几个参数:

  • PrintClassHistogramBeforeFullGC
    • 这个参数是说在full gc前会将内存中的对象以日志的形式输出,但是很多大对象都是些byte啊啥的,你压根不知道是那个对象引用的。
  • HeapDumpBeforeFullGC
    • 这个参数就是full gc前将hprof文件保存下来
  • HeapDumpPath
    • dump下来的hprof文件存放位置

通过上述操作,在应用下一次full gc的时候便会保存hprof文件文件

分析hprof文件

通过上述命令保存下来的文件大概有1.3G,有点大。

下载下来会比较麻烦。

这里通过MAT的linux的工具直接在服务器上进行分析。

MAT分析工具
从这个网站上下载Linux (x86_64/GTK+)

如何使用?
cd mat
./ParseHeapDump.sh /elab/spring-boot/dump.hprof  org.eclipse.mat.api:suspects org.eclipse.mat.api:overview org.eclipse.mat.api:top_components# 预计五分钟之后出结果,查看结果就到hprof所在的位置

/elab/spring-boot/dump.hprof : 位置

-rw-r--r-- 1 root root 8.3M Mar 20 10:15 java_pid18881.a2s.index
-rw-r--r-- 1 root root  13M Mar 20 10:15 java_pid18881.domIn.index
-rw-r--r-- 1 root root  37M Mar 20 10:15 java_pid18881.domOut.index
-rw------- 1 root root 1.3G Mar 20 10:01 java_pid18881.hprof
-rw-r--r-- 1 root root 295K Mar 20 10:16 java_pid18881.i2sv2.index
-rw-r--r-- 1 root root  33M Mar 20 10:15 java_pid18881.idx.index
-rw-r--r-- 1 root root  50M Mar 20 10:15 java_pid18881.inbound.index
-rw-r--r-- 1 root root 7.2M Mar 20 10:15 java_pid18881.index
-rw-r--r-- 1 root root 100K Mar 20 10:15 java_pid18881_Leak_Suspects.zip
-rw-r--r-- 1 root root  12M Mar 20 10:15 java_pid18881.o2c.index
-rw-r--r-- 1 root root  33M Mar 20 10:15 java_pid18881.o2hprof.index
-rw-r--r-- 1 root root  28M Mar 20 10:15 java_pid18881.o2ret.index
-rw-r--r-- 1 root root  49M Mar 20 10:15 java_pid18881.outbound.index
-rw-r--r-- 1 root root  82K Mar 20 10:15 java_pid18881_System_Overview.zip
-rw-r--r-- 1 root root 356K Mar 20 10:15 java_pid18881.threads
-rw-r--r-- 1 root root 256K Mar 20 10:16 java_pid18881_Top_Components.zip

一共会有这么些东西,你只要关注3个*.zip包就行了。
把这3个下载到本地,里面是html文件,打开就是结果。
主要关注 : java_pid18881_Leak_Suspects.zip 这个文件
打开结果:
在这里插入图片描述

我们看到有一个216M的大对象出现了。

然后点击链接进去看是那个线程造成的.
在这里插入图片描述
我们这里就找到了具体业务触发的方法了。

我这里就不贴具体的方法了,最根本的原因是一个图片压缩的功能造成的

Thumbnails.of(file.getInputStream()).scale(0.1f).toFile(outputImg);

如果客户端上传的图片太大,会通过这个方法进行压缩。由于对象本身会很大的话,很容易触发Full GC。

然后我根据这个时间点去监控系统中查询该URL的方法日志的时候,也发现了一个超过9秒的请求,根据方法执行的时间链路基本上也就确定了就是上述代码造成的。

好了,具体过程就是这样。

总结一下 :

  1. 通过开启JVM的参数,在full GC前保留一份hprof文件。
  2. 通过MAT的linux工具直接在服务器上分析,避免文件过大下载下来太慢。
  3. 然后查看结果页来找到具体的大对象

如果你还有什么更好的排查思路以及工具欢迎交流。

这篇关于纯干货:大对象导致FullGC频繁的原因及实践思路的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/665238

相关文章

JAVA利用顺序表实现“杨辉三角”的思路及代码示例

《JAVA利用顺序表实现“杨辉三角”的思路及代码示例》杨辉三角形是中国古代数学的杰出研究成果之一,是我国北宋数学家贾宪于1050年首先发现并使用的,:本文主要介绍JAVA利用顺序表实现杨辉三角的思... 目录一:“杨辉三角”题目链接二:题解代码:三:题解思路:总结一:“杨辉三角”题目链接题目链接:点击这里

Docker集成CI/CD的项目实践

《Docker集成CI/CD的项目实践》本文主要介绍了Docker集成CI/CD的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录一、引言1.1 什么是 CI/CD?1.2 docker 在 CI/CD 中的作用二、Docke

java中VO PO DTO POJO BO DO对象的应用场景及使用方式

《java中VOPODTOPOJOBODO对象的应用场景及使用方式》文章介绍了Java开发中常用的几种对象类型及其应用场景,包括VO、PO、DTO、POJO、BO和DO等,并通过示例说明了它... 目录Java中VO PO DTO POJO BO DO对象的应用VO (View Object) - 视图对象

Spring中Bean有关NullPointerException异常的原因分析

《Spring中Bean有关NullPointerException异常的原因分析》在Spring中使用@Autowired注解注入的bean不能在静态上下文中访问,否则会导致NullPointerE... 目录Spring中Bean有关NullPointerException异常的原因问题描述解决方案总结

MySQL的索引失效的原因实例及解决方案

《MySQL的索引失效的原因实例及解决方案》这篇文章主要讨论了MySQL索引失效的常见原因及其解决方案,它涵盖了数据类型不匹配、隐式转换、函数或表达式、范围查询、LIKE查询、OR条件、全表扫描、索引... 目录1. 数据类型不匹配2. 隐式转换3. 函数或表达式4. 范围查询之后的列5. like 查询6

使用Vue.js报错:ReferenceError: “Vue is not defined“ 的原因与解决方案

《使用Vue.js报错:ReferenceError:“Vueisnotdefined“的原因与解决方案》在前端开发中,ReferenceError:Vueisnotdefined是一个常见... 目录一、错误描述二、错误成因分析三、解决方案1. 检查 vue.js 的引入方式2. 验证 npm 安装3.

vue如何监听对象或者数组某个属性的变化详解

《vue如何监听对象或者数组某个属性的变化详解》这篇文章主要给大家介绍了关于vue如何监听对象或者数组某个属性的变化,在Vue.js中可以通过watch监听属性变化并动态修改其他属性的值,watch通... 目录前言用watch监听深度监听使用计算属性watch和计算属性的区别在vue 3中使用watchE

Java将时间戳转换为Date对象的方法小结

《Java将时间戳转换为Date对象的方法小结》在Java编程中,处理日期和时间是一个常见需求,特别是在处理网络通信或者数据库操作时,本文主要为大家整理了Java中将时间戳转换为Date对象的方法... 目录1. 理解时间戳2. Date 类的构造函数3. 转换示例4. 处理可能的异常5. 考虑时区问题6.

流媒体平台/视频监控/安防视频汇聚EasyCVR播放暂停后视频画面黑屏是什么原因?

视频智能分析/视频监控/安防监控综合管理系统EasyCVR视频汇聚融合平台,是TSINGSEE青犀视频垂直深耕音视频流媒体技术、AI智能技术领域的杰出成果。该平台以其强大的视频处理、汇聚与融合能力,在构建全栈视频监控系统中展现出了独特的优势。视频监控管理系统EasyCVR平台内置了强大的视频解码、转码、压缩等技术,能够处理多种视频流格式,并以多种格式(RTMP、RTSP、HTTP-FLV、WebS

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M