一、问题是怎么发现的

最近有个新系统开发完成后要上线,由于系统调用量很大,所以先对核心接口进行了一次压力测试,由于核心接口中基本上只有纯内存运算,所以预估核心接口的压测QPS能够达到上千。

压测容器配置:4C8G

先从10个并发开始进行发压,结果cpu一下就飙升到了100%,但是核心接口的qps才200左右。于是观察jvm的垃圾回收发现younggc很频繁,但是fullGC数量为零。

二、排查问题的详细过程

由于刚一开始压测,容器cpu就飙升到了100%,所以需要先定位cpu使用率问题,找出使用cpu最高的几个进程。可以通过top命令查找进程ID,发现正是压测的Java应用进程ID;然后在定位该金晨曦cpu使用率最高的线程,可以通过top -p 进程ID -H 命令显示该进程下的线程使用cpu信息。

top

top -p 进程ID -H

图片中PID列则为十进制显示的线程ID,然后转换为16进制;在通过jstack 系统进程ID | grep 16进制线程ID 命令找到对应的线程信息如下,也就是该线程占用了一半左右的cpu。

jstack 系统进程ID | grep 16进制线程ID

此时定位到了Finalizer线程,但是这个线程又有什么作用呢?

原来这个线程会不停的循环等待java.lang.ref.Finalizer.ReferenceQueue中的新增对象。一旦Finalizer线程发现队列中出现了新的对象,它会弹出该对象,调用它的finalize()方法,将该引用从Finalizer类中移除,因此下次GC再执行的时候,这个Finalizer实例以及它引用的那个对象就可以被垃圾回收掉了。如果这个线程一直在不停的工作,说明Finalizer的队列中有许多等待GC的垃圾对象。此时可以通过另一个命令来查看等待回收的垃圾对象有哪些。

jmap -finalizerinfo 进程ID

Count Class description
-------------------------------------------------------
32221 com.jd.price.deep.exact.entity.coupons.DeepExactCouponVo$$EnhancerByCGLIB$$200e6ee6
14908 com.jd.pricedoor.compute.promotion.MultiplePromotion$$EnhancerByCGLIB$$a59933de
11982 java.util.zip.Deflater
1 java.net.SocksSocketImpl

通过上述结果可以发现有好多的业务对象,通过类名可以看到这些对象都是通过CGLIB动态代理创建的,而且这些动态代理类都默认实现了finalize方法,导致这些对象在进行垃圾回收时必须先要执行finalize方法,所以都积压到了finalizer的队列中。

三、如何解决问题

通过上述排查过程发现,是由于大量的业务对象通过CGLIB创建了动态代理类,而这些代理都是系统处理请求时创建的临时对象,请求完成后,这些临时对象就需要被垃圾回收掉,从而导致Finalizer线程执行频繁抢占了cpu资源。

针对以上分析结果所以有了如下几种解决方案:

1.不要使用CGLIB来给那些需要频繁进行垃圾回收的对象创建动态代理,可以手动创建静态代理类。

2.对象复用,尽量减少临时对象的产生。

作者:京东零售 曹志飞

来源:京东云开发者社区

CGLIB动态代理对象GC问题排查的更多相关文章

  1. Spring框架中的JDK与CGLib动态代理

    JDK和CGLib动态代理区别 JDK动态代理:利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类, 在调用具体方法前调用InvokeHandler ...

  2. jdk动态代理和cglib动态代理底层实现原理详细解析(cglib动态代理篇)

    代理模式是一种很常见的模式,本文主要分析cglib动态代理的过程 1. 举例 使用cglib代理需要引入两个包,maven的话包引入如下 <!-- https://mvnrepository.c ...

  3. Java代理:静态代理、JDK动态代理和CGLIB动态代理

    代理模式(英语:Proxy Pattern)是程序设计中的一种设计模式.所谓的代理者是指一个类别可以作为其它东西的接口.代理者可以作任何东西的接口:网络连接.存储器中的大对象.文件或其它昂贵或无法复制 ...

  4. CGLib动态代理原理及实现

    JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了.CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采 ...

  5. 【Java EE 学习 51】【Spring学习第三天】【cglib动态代理】【AOP和动态代理】【切入点表达式】

    一.cglib动态代理 1.简介 (1)CGlib是一个强大的,高性能,高质量的Code生成类库.它可以在运行期扩展Java类与实现Java接口. (2) 用CGlib生成代理类是目标类的子类. (3 ...

  6. JDK动态代理与CGLib动态代理

    1.JDK动态代理 JDK1.3以后java提供了动态代理技术,允许开发者在运行期创建接口的代理实例,动态代理是实现AOP的绝好底层技术. JDK的动态代理主要涉及到java.lang.reflect ...

  7. Java代理(jdk静态代理、动态代理和cglib动态代理)

    一.代理是Java常用的设计模式,代理类通过调用被代理类的相关方法,并对相关方法进行增强.加入一些非业务性代码,比如事务.日志.报警发邮件等操作. 二.jdk静态代理 1.业务接口 /** * 业务接 ...

  8. [z]Java代理(jdk静态代理、动态代理和cglib动态代理)

    一.代理是Java常用的设计模式,代理类通过调用被代理类的相关方法,并对相关方法进行增强.加入一些非业务性代码,比如事务.日志.报警发邮件等操作. 二.jdk静态代理 1.业务接口 1 2 3 4 5 ...

  9. Atitit 代理CGLIB 动态代理 AspectJ静态代理区别

    Atitit 代理CGLIB 动态代理 AspectJ静态代理区别 1.1. AOP 代理主要分为静态代理和动态代理两大类,静态代理以 AspectJ 为代表:而动态代理则以 spring AOP 为 ...

  10. Spring学习总结(二)——静态代理、JDK与CGLIB动态代理、AOP+IoC

    一.为什么需要代理模式 假设需实现一个计算的类Math.完成加.减.乘.除功能,如下所示: package com.zhangguo.Spring041.aop01; public class Mat ...

随机推荐

  1. 在docker容器里,ffmpeg给视频文件内嵌字幕文件,不生效,如何解决?

    用ffmpeg命令,发现执行成功,但视频文件就是没有字幕.看不出问题出现在什么地方.后来直接用ffmpeg添加水印命令测试,发现是缺少字体文件,如下图所示: 报Fontconfig error: Ca ...

  2. 2022-05-22:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p

    2022-05-22:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先. 百度百科中最近公共祖先的定义为:"对于有根树 T 的两个节点 p.q,最近公共祖先表示为一个节点 x,满足 x ...

  3. 2022-02-05:字典序的第K小数字。 给定整数 n 和 k,找到 1 到 n 中字典序第 k 小的数字。 注意:1 ≤ k ≤ n ≤ 10**9。 示例 : 输入: n: 13 k: 2

    2022-02-05:字典序的第K小数字. 给定整数 n 和 k,找到 1 到 n 中字典序第 k 小的数字. 注意:1 ≤ k ≤ n ≤ 10**9. 示例 : 输入: n: 13 k: 2 输出 ...

  4. vue全家桶进阶之路13:生命周期

    Vue2的生命周期是指Vue实例从创建.挂载.更新.销毁等各个阶段中所经历的一系列过程.Vue2的生命周期共有8个阶段,分别是: beforeCreate:Vue实例被创建之前的阶段,此时Vue实例的 ...

  5. 痞子衡嵌入式:MCUBootUtility v5.0发布,初步支持i.MXRT1180

    -- 痞子衡维护的NXP-MCUBootUtility工具距离上一个大版本(v4.0.0)发布过去4个多月了,期间痞子衡也做过两个小版本更新,但不足以单独介绍.这一次痞子衡为大家带来了全新大版本v5. ...

  6. Vuex modules 中active相互调用

    大中型项目中使用vuex进行状态管理时,经常会按模块分割到不同的module中去,而操作中难免有模块中的active相互调用的情况,然而有时也会出现一些问题,这里顺便记录下 store目录结构 在us ...

  7. python学习之-------OS 文件夹和文件操作

    # OS模块 :查看一个文件夹下所有文件,这个文件夹有文件夹,不能用walk# -- coding: UTF-8 --import osimport sys#C:\Users\Administrato ...

  8. Linux 下 PostgreSQL 源码编译安装

    由于微信不允许外部链接,你需要点击文章尾部左下角的 "阅读原文",才能访问文中链接. PostgreSQL 是一个功能强大的开源对象关系数据库管理系统(ORDBMS),它从伯克利写 ...

  9. SQLLDR简介 和 Oracle插入大量数据

    SQLLDR简介 一.简介 SQLLOADER是ORACLE的数据加载工具,通常用来将操作系统文件(数据)迁移到ORACLE数据库中.SQLLOADER是大型数据仓库选择使用的加载方法,因为它提供了最 ...

  10. JavaScript 显示数据

    JavaScript 显示数据 JavaScript 可以通过不同的方式来输出数据: 使用 window.alert() 弹出警告框. 使用 document.write() 方法将内容写到 HTML ...