IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 一次线上频繁FullGC的排查 -> 正文阅读

[Java知识库]一次线上频繁FullGC的排查

背景

一日,线上的某个服务的某个节点突然告警,频繁地FullGC,这个服务已经有半个月没有进行过发布和容器重启了。

处理步骤

  • 首先将告警的容器隔离,从网关上摘掉这个节点,让流量不再进入到这个节点。
  • 通过jmap将节点的内存快照dump下来。
  • 通过jprofiler分析hprof文件。

分析原因

有很多工具可以方便地分析hprof文件,如MAT、JProfiler。
我们通过JProfiler分析,在JProfiler的启动中心打开单个快照。
在这里插入图片描述
选择下载到本地的hprof文件,等待一会解析,然后直奔“最大对象”:
在这里插入图片描述
发现一个static字段占用了1851MB大小,差不多2GB!!
在这里插入图片描述
我们的JVM启动参数中有如下关于内存的设置:

-Xms8192m 
-Xmx8192m 
-Xmn5120m 
-XX:MetaspaceSize=384m 
-XX:MaxMetaspaceSize=512m 

即,java堆内存分配8GB,新生代堆内存5GB,那么留给老年代的就只剩3GB,然后那一个ConcurrentHashMap类型的static字段,就占了将近2GB(这个大对象很显然是放在老年代的)。
我们知道JVM垃圾回收的时候,是通过可达性分析来判断一个对象是否存活的,凡是能从GCRoots到达的对象都不会被回收,而static字段就是GCRoots的一种,也就是说我们的这个static字段是没办法被回收的。所以当发生FullGC的时候总是无法在老年代腾出空间,这样JVM很快又要进行FullGC,但是每次FullGC都回收不到足够的空间,从而陷入恶性循环。

解决问题

通过查看代码中的那个static ConcurrentHashMap,发现是中间件的一个类中的字段,用于存放流量的灰度标识,只有往里面放内容,却没有删除的代码。那么如果map的key基本上都不一样,就会导致map中的内容随着时间的流逝而不断地变大,最终导致FullGC的时候,回收不掉老年代中的内存。
这个问题,在前一段时间已经有别的服务也遇到了,后来反馈给中间件,中间件那边给了一个解决了该问题的版本让升级。
那么为什么以前没升级的时候没有出现问题?我猜测可能是上游网关更改了流量灰度标识的规则,导致往map里面放的内容的key突然变得花样多了起来,这样map就不能很好滴去重,导致map不断变大。而当时写中间件这块代码的人可能因为当时认为不会有那么多样的key,认为map不会变得太大,所以就没有删除map中的内容。
查看了中间件升级的版本,采用了guava的cache,设定了一个maxsize,这样map中的元素数量就不会超过maxsize,也就不会导致老年代被占用那么大。这其实就是一种缓存淘汰策略,只保留最近使用的maxsize条记录。

反思

  1. JVM的内存问题,很多的时候并不是简单地把堆内存设置大一点就可以解决的,如果代码有问题,总会把内存耗尽,这个时候就得通过修改代码来解决问题了。
  2. 有些内存泄露,不是很快就出现问题,而是很久以后才出问题的,比如我们的这个服务,半个月没重新启动,导致老年代被慢慢占用到无法回收。看来提高发布的频率也是有可能将一些隐藏的内存泄露问题掩盖住的。
  3. 本地缓存可以提高速度,但是要小心,看看是否需要清除不用的内容,比如采用guava的cache,设定一个固定的大小可以有效避免内存泄露。
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-13 21:36:26  更:2022-03-13 21:40:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 9:51:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码