JVM3_数据库连接池虚引用ConnectionFinalizerPhantomReference引起的FullGC问题排查

news2024/10/23 14:23:48

背景

XOP服务运行期间,查看Grafana面板,发现堆内存周期性堆积,Full GC时间略长,需要调查下原因

image.png

目录

  • 垃圾收集器概述
    • 常见的垃圾收集器
    • 分区收集策略
    • 为什么CMS没成为默认收集器
  • 查看JVM运行时环境
  • 分析快照
    • PhantomReference虚引用

1、垃圾收集器概述

常见的垃圾收集器

按照收集策略划分

  • 新生代收集器:Serial、ParNew、Parallel Scavenge;
  • 老年代收集器:Serial Old、Parallel Old、CMS;
  • 整堆分区收集器:G1、ZGC、Shenandoah

吞吐量优先、停顿时间优先

  • 吞吐量优先:Parallel Scavenge收集器、Parallel Old 收集器。
  • 停顿时间优先:CMS(Concurrent Mark-Sweep)收集器。

吞吐量与停顿时间适用场景

  • 吞吐量优先:交互少,计算多,适合在后台运算的场景。
  • 停顿时间优先:交互多,对响应速度要求高

串行、并行、并发

  • 串行:Serial、Serial Old,垃圾回收必须暂停全部工作线程,无法利用多核优势。
  • 并行:ParNew、Parallel Scavenge、Parallel Old,并行描述的是多条垃圾收集器线程之前的关系,说明同一时间有多条垃圾收集器线程在工作,此时用户线程默认是处于等待状态。
  • 并发:CMS、G1,并发描述的是垃圾收集器线程和用户线程之间的关系

算法,参考往期博客

  • 复制算法:Serial、ParNew、Parallel Scavenge、G1
  • 标记-清除:CMS
  • 标记-整理:Serial Old、Parallel Old、G1

通过参数选择需要使用的垃圾收集器

  • -XX:+UseSerialGC,虚拟机运行在Client模式下的默认值,Serial+Serial Old。
  • -XX:+UseParNewGC,ParNew+Serial Old,在JDK1.8被废弃,在JDK1.7还可以使用。
  • -XX:+UseConcMarkSweepGC,ParNew+CMS+Serial Old。
  • -XX:+UseParallelGC,虚拟机运行在Server模式下的默认值,Parallel Scavenge+Serial Old(PS Mark Sweep)。
  • -XX:+UseParallelOldGC,Parallel Scavenge+Parallel Old。
  • -XX:+UseG1GC,G1+G1。

分区收集策略

JDK7/8使用采用分代收集比较多的垃圾收集器组合

image.png另外随着JDK版本更新,JDK9之后默认的垃圾收集器为G1,之前分代收集思想逐渐被分区收集思想代替,考虑的是收集堆内存的哪个部分才能获得收益最大,如G1、ZGC-JDK15开始准备好生产了、Shenandoah,并且随着JDK的版本的升级吞吐量、响应速度都在不断优化提升。

  • G1:开创了垃圾收集器面向局部收集的设计思路 和 基于Region的内存布局形式。不再像之前那样划代,而是把连续的堆内存划分为一块块的Region,每一个Region都可以根据需要充当之前分代区域的Eden、Survivor、老年代空间,除此之外还有一类特殊的Humongous区域专门用于存储大对象。它可以面向堆内存任何部分来组成回收集(Collection Set),衡量标准不再是它属于哪个分代,而是哪块内存中存放的垃圾数量最多,回收收益最大,优先处理回收收益最大的那些 Region,这也就是 Garbage First 名字的由来。
  • Shennandoah:一款RedHat独立开发后来贡献给OpenJDK的收集器,在OracleJDK不存在,目标之一是暂停时间与堆大小无关,并且经过优化,中断时间不超过几毫秒。
  • ZGC:目标和Shennandoah类似,希望在对吞吐量影响不大的情况下(相比G1应用程序吞吐量减少不超过15%),实现任意堆内存大小都可以吧垃圾收集器停顿时间限制在十毫秒内。

深入学习参考

  • GC - Java 垃圾回收器之G1详解
  • Java Hotspot G1 GC的一些关键技术-美团技术团队
  • 新一代垃圾回收器ZGC的探索与实践-美团技术团队

为什么CMS从来没成为默认收集器

CMS(Concurrent Mark Sweep)是一种 以获取最短回收停顿时间为目标 的收集器。
在 JDK 5 发布时,HotSpot 虚拟机推出了一款在强交互应用中具有划时代意义的垃圾收集器——CMS 收集器。这款收集器是 HotSpot 中第一款真正意义上支持并发的垃圾收集器,它首次实现了让垃圾收集线程与用户线程(基本上)同时工作。
CMS 比 G1 早不了多少。CMS 从 JDK 5 开始加入,6 成熟;而 G1 是 7 加入,8 成熟,9 正式成为默认 GC 策略。此时 CMS 就被标记为 Deprecated,随后在 JDK 14 中被移除。

CMS并不是一个非常成功的GC策略,GC优化一般考虑点是吞吐量和响应时间,而CMS

  • 采用标记-清除算法,当处理器核比较少的时候,会造成比较大的负载,而且容易产生内存碎片,碎片太多无能为力的时候触发Concurrent Mode Failure还需要Serial Old来擦屁股。
  • 仅针对老年代,还需要一个新生代收集器,但是和Parallel Scavenage又不兼容,只能选择性能不如Parallel Scavenage的PerNew。
  • 需要调整的参数比较多,比G1多一倍

以上的种种,造成的结果就是 ParNew + CMS + Serial Old 的组合工作起来其实并不稳定。为了得到 CMS 那一点好处,需要付出很多的代价(包括 JVM 调参)。
CMS 相比前辈们,没有带来革命性的改变;而它的后辈们比它强太多。它自身的实现又很复杂,兼容性又差,调参也很麻烦,所以无法成为默认 GC 方案了。

参考

  • Java——七种垃圾收集器+JDK11最新ZGC
  • 面试:JVM 垃圾回收器-腾讯云开发者社区-腾讯云
  • Java 8 vs Java 17 垃圾收集器

2、查看JVM运行时环境

数据库环境是MySQL,连接池使用的是HikariPool,驱动是mysql-connector-java-8.0.21.jar,当前生产环境JVM运行参数

root     14968     1  0 223 ?       00:41:51 

java -server 

-XX:MetaspaceSize=160m 
-XX:MaxMetaspaceSize=160m 
-Xms1024m 
-Xmx1024m 
-Xss256k 
-Duser.timezone=GMT+08 
-XX:+UseParNewGC 
-XX:+UseConcMarkSweepGC 
-XX:+CMSParallelRemarkEnabled 
-XX:CMSInitiatingOccupancyFraction=80 
-XX:+UseCMSInitiatingOccupancyOnly 
-XX:+HeapDumpOnOutOfMemoryError 
-XX:HeapDumpPath=/data/serviceroot/xkw-xopqbm-api-service/xkw-xopqbm-api-service.hprof 
-XX:+PrintGCDetails 
-XX:+PrintGCDateStamps 
-Xloggc:/data/serviceroot/xkw-xopqbm-api-service/logs/xkw-xopqbm-api-service-gc.log 
-XX:+UseGCLogFileRotation 
-XX:NumberOfGCLogFiles=10 
-XX:GCLogFileSize=1m 

-jar /data/serviceroot/xkw-xopqbm-api-service/xkw-xopqbm-api-service.jar 
--spring.profiles.active=test 
--server.port=9501 
-Dons.client.logLevel=ERROR

当前服务器的java版本为1.8

[root@localmdmtest ~]# java -version
java version "1.8.0_281"
Java(TM) SE Runtime Environment (build 1.8.0_281-b09)
Java HotSpot(TM) 64-Bit Server VM (build 25.281-b09, mixed mode)

查看使用的垃圾收集器 jmap -heap pid,可以看到当前使用的垃圾收集器 ParNew+CMS+Serial Old

[root@localmdmtest ~]# jmap -heap 14968

Attaching to process ID 14968, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.281-b09

using parallel threads in the new generation.
using thread-local object allocation.


# Concurrent Mark-Sweep GC :CMS回收器
# Mark Sweep Compact GC:    串行GC(Serial GC)
# Parallel GC with 2 thread(s): 并行GC(ParNew)

# 这里看出是CMS
Concurrent Mark-Sweep GC

Heap Configuration:
   MinHeapFreeRatio         = 40
   MaxHeapFreeRatio         = 70
   MaxHeapSize              = 1073741824 (1024.0MB)
   NewSize                  = 357892096 (341.3125MB)
   MaxNewSize               = 357892096 (341.3125MB)
   OldSize                  = 715849728 (682.6875MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 167772160 (160.0MB)
   CompressedClassSpaceSize = 159383552 (152.0MB)
   MaxMetaspaceSize         = 167772160 (160.0MB)
   G1HeapRegionSize         = 0 (0.0MB)

Heap Usage:
New Generation (Eden + 1 Survivor Space):
   capacity = 322109440 (307.1875MB)
   used     = 245758352 (234.37342834472656MB)
   free     = 76351088 (72.81407165527344MB)
   76.2965382200534% used
Eden Space:
   capacity = 286326784 (273.0625MB)
   used     = 239080888 (228.00530242919922MB)
   free     = 47245896 (45.05719757080078MB)
   83.49930965592098% used
From Space:
   capacity = 35782656 (34.125MB)
   used     = 6677464 (6.368125915527344MB)
   free     = 29105192 (27.756874084472656MB)
   18.66117484403617% used
To Space:
   capacity = 35782656 (34.125MB)
   used     = 0 (0.0MB)
   free     = 35782656 (34.125MB)
   0.0% used
concurrent mark-sweep generation:
   capacity = 715849728 (682.6875MB)
   used     = 84539240 (80.6229019165039MB)
   free     = 631310488 (602.0645980834961MB)
   11.809634996466745% used

45864 interned Strings occupying 4725904 bytes.

3、分析快照

dump快照命令:jmap -dump:live,format=b,file=/home/scl/xopqbm/heapdump.hprof xxx,可以使用MAT或者在线工具https://heaphero.io/分析快照

发现11,319 instances of "com.mysql.cj.jdbc.AbandonedConnectionCleanupThread$ConnectionFinalizerPhantomReference"

image.png

也就是ConnectionFinalizerPhantomReference占了80%的堆内存,为什么会这么多对象,需要分析下原因。

PhantomReference虚引用

ConnectionFinalizerPhantomReference这个类在AbandonedConnectionCleanupThread类内定义,继承PhantomReference

// AbandonedConnectionCleanupThread类内
private static class ConnectionFinalizerPhantomReference extends PhantomReference<MysqlConnection> {
        private NetworkResources networkResources;

        ConnectionFinalizerPhantomReference(MysqlConnection conn, NetworkResources networkResources, ReferenceQueue<? super MysqlConnection> refQueue) {
            super(conn, refQueue);
            this.networkResources = networkResources;
        }

        void finalizeResources() {
            if (this.networkResources != null) {
                try {
                    this.networkResources.forceClose();
                } finally {
                    this.networkResources = null;
                }
            }
        }
    }

对于PhantomReference虚引用的概念,简单就是他可以将某个对象标记为虚的,一般用于标记对象是否被GC回收,虚引用也称为“幽灵引用”,它是最弱的一种引用关系。

image.png

  • 如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
  • 为一个对象设置虚引用关联的唯一目的只是为了能在这个对象被收集器回收时收到一个系统通知。
  • 当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在垃圾回收后,将这个虚引用加入引用队列,在其关联的虚引用出队前,不会彻底销毁该对象。所以可以通过检查引用队列中是否有相应的虚引用来判断对象是否已经被回收了。

查看AbandonedConnectionCleanupThread类内部的属性和主要的run方法,主要的属性有

  • Set connectionFinalizerPhantomRefs
  • ReferenceQueue referenceQueue
private static final Set<ConnectionFinalizerPhantomReference> connectionFinalizerPhantomRefs = ConcurrentHashMap.newKeySet();
    
private static final ReferenceQueue<MysqlConnection> referenceQueue = new ReferenceQueue<>();

    
private static final ExecutorService cleanupThreadExcecutorService;
    
private static Thread threadRef = null;
    
private static Lock threadRefLock = new ReentrantLock();

image.png

public void run() {
    for (;;) {
        try {
            checkThreadContextClassLoader();
            Reference<? extends MysqlConnection> reference = referenceQueue.remove(5000);
            if (reference != null) {
                finalizeResource((ConnectionFinalizerPhantomReference) reference);
            }
        } catch (InterruptedException e) {
            threadRefLock.lock();
            try {
                threadRef = null;

                // Finalize remaining references.
                Reference<? extends MysqlConnection> reference;
                while ((reference = referenceQueue.poll()) != null) {
                    finalizeResource((ConnectionFinalizerPhantomReference) reference);
                }
                connectionFinalizerPhantomRefs.clear();
            } finally {
                threadRefLock.unlock();
            }
            return;
        } catch (Exception ex) {
            // Nowhere to really log this.
        }
    }
}

// TODO

参考

  • JVM 优化踩坑记
  • 数据库连接池引起的FullGC问题,看我如何一步步排查、分析、解决
  • PhantomReference 引发的GC问题-CSDN博客
  • AbandonedConnectionCleanupThread$ConnectionFinalizerPhantomReference内存溢出_abandoned connection cleanup thread-CSDN博客
  • G1垃圾回收参数调优及MySQL虚引用造成GC时间过长分析 | 京东云技术团队 - 墨天轮

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1498265.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DAWG库下载出现的问题

今天配置一些环境出现了报错需要下载DAWG-0.8.0-cp38-cp38-win_amd64&#xff0c; PyPi官网https://pypi.org/project/DAWG/#files 只找到了mac版本&#xff0c;没发现windows版本 于是找到了非官方网址&#xff1a; https://www.lfd.uci.edu/~gohlke/pythonlibs/#dawg 下载DA…

JAVA开发第一个Springboot WebApi项目

一、创建项目 1、用IDEA新建一个SpringBoot项目 注意JDK与Java版本的匹配,如果想选择jdk低版本,先要更改服务器URL:start.aliyun.com 2、添加依赖 (1)、Lombok (2)、Spring Web (3)、Mybatis Framework (4)、MySqlDriver 项目中的配置 pom.xml 如下 <?…

java写DBF文件

之前漏了个功能支持&#xff0c;那就是WhoNet上报的DBF文件导出&#xff0c;因为DBF基本没什么人在用了&#xff0c;实现DbfUtil供业务写DBF文件做WhoNet上报导出用。 DBF读写工具类 package JRT.Core.Util;import com.linuxense.javadbf.DBFDataType; import com.linuxense.…

java017 - Java抽象类

1、概述 一般情况&#xff0c;动物是抽象的&#xff0c;所以不能被new,比如你在Animal类中定义一个成员方法eat,你不能定义具体内容&#xff0c;比如吃鱼或者吃白菜&#xff0c;因为动物是抽象的。 一个没有方法体的方法&#xff0c;应该定义为抽象方法&#xff0c;而类中如果…

Linux:kubernetes(k8s)探针ReadinessProbe的使用(9)

本章yaml文件是根据之前文章迭代修改过来的 先将之前的pod删除&#xff0c;然后使用下面这个yaml进行生成pod apiVersion: v1 # api文档版本 kind: Pod # 资源对象类型 metadata: # pod相关的元数据&#xff0c;用于描述pod的数据name: nginx-po # pod名称labels: # pod的标…

vulhub中ThinkPHP5 SQL注入漏洞 敏感信息泄露

漏洞原理 传入的某参数在绑定编译指令的时候又没有安全处理&#xff0c;预编译的时候导致SQL异常报错。然而thinkphp5默认开启debug模式&#xff0c;在漏洞环境下构造错误的SQL语法会泄漏数据库账户和密码 启动后&#xff0c;访问http://your-ip/index.php?ids[]1&ids[]2…

硬核程序员接单指南,速看!

程序员单没接着&#xff0c;时间还浪费了&#xff1f;惹得一身晦气。遇上了1k开发一个“淘宝”网站的“深井”&#xff1f;不是来下单的&#xff0c;倒像是来许愿的……估摸着是把程序员当阿拉丁神灯。 莫非那些兼职月入3k&#xff0b;的人&#xff0c;都是托儿&#xff1f;带着…

【Leetcode每日一题】 前缀和 - 和为 K 的子数组(难度⭐)(29)

1. 题目解析 题目链接&#xff1a;560. 和为 K 的子数组 这个问题的理解其实相当简单&#xff0c;只需看一下示例&#xff0c;基本就能明白其含义了。 核心在于计算题目所给数组是否存在连续子数组和为指定值&#xff0c;存在返回连续子数组个数即可&#xff0c;不存在返回0即…

外包干了8天,技术退步明显。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;19年通过校招进入杭州某软件公司&#xff0c;干了接近3年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

击鼓传花游戏

有N个小朋友围成一圈玩击鼓传花游戏&#xff0c;将小朋友编号为1-N&#xff0c;从1号开始传花&#xff0c;每次传3个&#xff0c;拿到花的小朋友表演节目后退出。任给N&#xff0c;问最后一个表演的小朋友编号是多少&#xff1f;例如&#xff1a;输入5&#xff0c;从1号开始传花…

网站维护3年15000元,贵不贵?市场价多少

一般来说&#xff0c;给公司做好网站上线之后&#xff0c;网站就进入了运维期间&#xff0c;某功力公司给客户收费3年15000元网站运维费用&#xff0c;到底高不高呢&#xff1f; 首先&#xff0c;来看看网站运维都有哪些项目 网站运维涉及多个项目和任务&#xff0c;包括但不限…

M1电脑 Xcode15升级遇到的问题

遇到四个问题 一、模拟器下载经常报错。 二、Xcode15报错: SDK does not contain libarclite 三、报错coreAudioTypes not found 四、xcode模拟器运行一次下次必定死机 一、模拟器下载经常报错。 可以https://developer.apple.com/download/all/?qios 下载最新的模拟器&…

鸿蒙开发岗成春招最大黑马,“金三银四”应届生如何突围?

一年一度春招时间到&#xff0c;技术岗位已成为众多人才竞相追求的“职业高地”&#xff0c;也是未来职业发展的重要方向之一。鸿蒙人才在春招市场上成为“香饽饽”&#xff0c;与往年不同的是&#xff0c;许多应届生放弃考公执念向程序员进攻&#xff0c;这一现象背后蕴含着深…

程序逻辑控制

1.java的三大结构 可以说java的这三大结构包括其中的语句跟c语言上的基本上都是一样的。现在就当重新复习一遍吧&#xff01; 1.顺序结构 2.分支结构 if语句 跟c语言的语法一模一样。就直接看文案了。 switch语句 java中的switch语句跟c语言中的switch几乎相同&#xff0c;…

试用Claude3

1 简介 好消息是&#xff0c;2024 年 3 月 4 日发布了 Claude3&#xff0c;据传比 GPT-4 更好&#xff0c;snooet 版本可以免费试用&#xff0c;坏消息是我们这儿不能用。 在官网注册时&#xff0c;需要选择国家并使用手机接收短信验证码。而在选项中没有中国这个选项。即使成…

腾讯云学生服务器多少钱?怎么申请?

2024年腾讯云学生服务器优惠活动「云校园」&#xff0c;学生服务器优惠价格&#xff1a;轻量应用服务器2核2G学生价30元3个月、58元6个月、112元一年&#xff0c;轻量应用服务器4核8G配置191.1元3个月、352.8元6个月、646.8元一年&#xff0c;CVM云服务器2核4G配置842.4元一年&…

一周学会Django5 Python Web开发-Django5新增视图CreateView

锋哥原创的Python Web开发 Django5视频教程&#xff1a; 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计29条视频&#xff0c;包括&#xff1a;2024版 Django5 Python we…

12.WEB渗透测试-Linux系统管理、安全加固(下)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;11.WEB渗透测试-Linux系统管理、安全加固&#xff08;上&#xff09;-CSDN博客 Linux任务…

Numpy 数组转换为 Pandas DataFrame

参考&#xff1a;Convert Numpy Array to Pandas DataFrame Numpy 介绍 Numpy是Python中一个非常强大的科学计算库&#xff0c;它提供了许多高效的数组操作方法。Pandas是另一个重要的数据处理库&#xff0c;它基于Numpy&#xff0c;并提供了更高级别的数据分析和处理工具。在…

横琴正式封关运行,惟客数据都做了什么?

​作为中国实施高水平制度型开放的重大探索&#xff0c;位于珠海横琴岛的横琴粤澳深度合作区于2024年3月1日零时正式实施分线管理封关运行&#xff0c;共设1个“一线”口岸、7个“二线”海关作业现场&#xff0c;覆盖旅检、货运、通关、稽&#xff08;核&#xff09;查等多线条…