java内存异常使用导致full gc频繁

 更新时间:2023年04月19日 08:19:20   作者:IntoTw  
Full GC是Java虚拟机中垃圾回收的一种方式,它会暂停应用程序所有的线程并清理整个堆内存。频繁的Full GC会导致应用程序的性能下降,甚至出现长时间的停顿。Java内存异常使用常常是Full GC频繁出现的原因之一,如使用大量的静态变量、内存泄漏等。

问题系统

日常巡检发现,应用线上出现频繁full gc

现象

应用线上出现频繁full gc


排查过程

分析dump

拉dump文件:小插曲:dump时如果指定:live,则在dump前jvm会先进行一次full gc,并且gc log里会打印dump full gc,这种对非内存泄漏导致的线上异常内存情况排查反而会带来不便,导致我们多dump了好几次。

分析dump文件:

a. 发现大量long[]数组占用最大空间,有异常情况


b. 查看gc根节点,发现这些long[]数据大部分是被org.HdrHistogram.Histogram持有,每个Histogram对象会持有一个2048size的long[]

c. 查看Histogram实例的数量,竟然有5w个,对比下正常项目的堆栈,大约是100倍


d. 这里又有一个插曲,一开始习惯用mat分析,但是mat生成的报告对分析泄露比较有用,对于分析异常的内存没有jvisualvm.exe和idea的profiler好用

排查原因

本地启动,可以复现这个类的内存使用情况,于是本地起一个其他内存正常的服务与有问题的应用,分析内存对比

这里用的是idea的profiler,很方便

发现差异:

对比正常的应用,发现异常应用的引用存在异常的来自

● rx.internal.operators.OnSubscribeReduceSeed$ReduceSeedSubscriber的引用,怀疑就是这个异常引用就是导致这些实例无法在新生代回收而是堆积到了老年代触发full gc的原因

排查差异:

简单看了下相关代码,看不出个所以然,直接debug对比

系统确实走进了相关的代码,增加了对Histogram的引用,而正常应用没有

但是光这样也看不出来为什么,此时关注到了左下角的线程池,这个线程池比较奇怪,是Metric的线程池
Metric是Hystrix用来统计相关指标,来供自己的dashboard或者用户来获取,以此来了解系统熔断相关参数和指标的功能
再看堆栈,走到这里的逻辑是


这个流用来统计单位时间内的系统指标,导致Hystrix使用Histogram的long数组实现类似滑动窗口的效果统计单位时间内的指标
Histogram本身是Hystrix用来实现类似桶+滑动窗口的功能,来统计单位时间内的流量,但是因为开启了指标参数,导致hystrix为了统计更长时间范围内的指标,新增了对象持有更多(单位时间内)的Histogram引用来聚合,这部分引用因为是统计更长时间范围周期的,就会因为引用持有时间长而到老年代,但是本质并不是内存泄漏,所以每次full gc后又可以得到回收

解决问题

看到上面的差异和怪异的线程池,第一反应就是关闭metric使应用不走到这段逻辑中增加引用,看官方文档,该配置默认是打开的,并且确认该功能只影响指标统计不影响断路器本身功能,使用配置hystrix.metrics.enabled=false配置来关闭
新增配置后,验证并查看堆栈,引用恢复正常,并且系统在一段时间后并没有新增更多的Histogram实例,发布线上后观察一段时间,full gc问题确实得到解决

根本原因

在当时发现解决的办法并验证后,并没有时间去研究hystrix.metrics.enabled默认配置就是true但是其他应用没有出现这个full gc问题的原因, 先解决了之后后续再继续跟进排查根本原因防止其他项目也出现相同问题

之前发现可疑的线程池是HystrixMetricsPoller ,经过查看,该线程池由HystrixMetricsPollerConfiguration


类开启,主要依靠hystrix.metrics.enabled开启,但是默认是true,为什么其他项目没有开启呢?

搜了下源码,这个类的开启还和一个注解有关


对比了一下代码,果然只有异常的应用使用了这个注解,这个注解的目的是开启断路器

但是研究之后发现,不使用这个注解,熔断等功能依旧可用,原因是在spring-cloud高版本之后,spring通过使用hystrix封装openfeign的方法来使用熔断,而不是集成整个hystrix体系,可能spring-cloud也发现了hystrix内存使用上的问题

所以在较高版本(起码我们的版本),feign是通过feign.hystrix.enabled来开关断路器的(这个开关是关闭的话,单纯加@EnableCircuitBreaker注解断路器是不会生效的)

其实在更高点版本的spring-cloud中,@EnableCircuitBreaker这个注解已经被标注为废弃了,但是可能因为我们是中间版本,所以存在既没有标注废弃其实又没有什么用的情况

总而言之,feign的断路功能只通过feign.hystrix.enabled来控制,增加@EnableCircuitBreaker注解之后仅仅只是会开启Hystrix其他所有的指标等功能


问题总结

问题根本原因

本次问题产生的根本原因是因为开启了@EnableCircuitBreaker注解,开启了Hystrix指标功能,导致Histogram实例大量进入老年代,只有full gc才可以回收
Histogram本身是Hystrix用来实现类似桶+滑动窗口的功能,来统计单位时间内的流量,但是因为开启了指标参数,导致hystrix为了统计更长时间范围内的指标,新增了对象持有更多(单位时间内)的Histogram引用来聚合,这部分引用因为是统计更长时间范围周期的,在访问量上升新生代复制速度变快时,就会因为引用持有时间长而到老年代,但是本质并不是内存泄漏,所以每次full gc后又可以得到回收

后续关注点 Spring-Cloud本身体系比较复杂,因为和Netfilx套件纠缠不清加上很多历史原因,能用明白某一个版本的就很不错了 开发本身并不了解这个版本断路器到底怎么开启,没有仔细看过对应版本的官方文档就去使用注解,在老版本,断路器确实是通过这个注解才能启用的 解决方式

关闭metric功能或者去掉@EnableCircuitBreaker注解均可解决
百度spring-cloud教程和文档时,一定一定一定要看对应版本的,否则可能加一堆配置解决某个问题,结果开启一大堆乱七八糟的功能

到此这篇关于java内存异常使用导致full gc频繁的文章就介绍到这了,更多相关java内存异常导致full gc频繁内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 微信企业号 根据错误码返回错误信息类封装

    微信企业号 根据错误码返回错误信息类封装

    这篇文章主要介绍了微信企业号 根据错误码返回错误信息类封装的相关资料,需要的朋友可以参考下
    2016-10-10
  • SpringCloud Feign集成AOP的常见问题与解决

    SpringCloud Feign集成AOP的常见问题与解决

    在使用 Spring Cloud Feign 作为微服务通信的工具时,我们可能会遇到 AOP 不生效的问题,这篇文章将深入探讨这一问题,给出几种常见的场景,分析可能的原因,并提供解决方案,希望对大家有所帮助
    2023-10-10
  • Java 精炼解读时间复杂度与空间复杂度

    Java 精炼解读时间复杂度与空间复杂度

    对于一个算法,其时间复杂度和空间复杂度往往是相互影响的,当追求一个较好的时间复杂度时,可能会使空间复杂度的性能变差,即可能导致占用较多的存储空间,这篇文章主要给大家介绍了关于Java时间复杂度、空间复杂度的相关资料,需要的朋友可以参考下
    2022-03-03
  • 详解Java中的日期类

    详解Java中的日期类

    这篇文章主要介绍了Java中的日期类的相关资料,帮助大家更好的利用Java处理时间,感兴趣的朋友可以了解下
    2020-10-10
  • 快速了解hibernate配置文件与映射文件

    快速了解hibernate配置文件与映射文件

    这篇文章主要介绍了快速了解hibernate配置文件与映射文件,具有一定参考价值,需要的朋友可以了解下。
    2017-10-10
  • 详解 Java HashMap 实现原理

    详解 Java HashMap 实现原理

    这篇文章主要介绍了详解 Java HashMap 实现原理的相关资料,帮助大家更好的理解和学习使用Java,感兴趣的朋友可以了解下
    2021-03-03
  • Spring整合Junit详解

    Spring整合Junit详解

    Spring 是目前主流的 Java Web 开发框架,是 Java 世界最为成功的框架。该框架是一个轻量级的开源框架,具有很高的凝聚力和吸引力,本篇文章带你了解如何配置数据源、注解开发以及整合Junit
    2022-07-07
  • mybatis同一张表多次连接查询相同列赋值问题小结

    mybatis同一张表多次连接查询相同列赋值问题小结

    这篇文章主要介绍了mybatis同一张表多次连接查询相同列赋值问题,非常不错,具有参考借鉴价值,需要的的朋友参考下
    2017-01-01
  • Struts2学习教程之Action类如何访问WEB资源

    Struts2学习教程之Action类如何访问WEB资源

    这篇文章主要给大家介绍了关于Struts2学习教程之Action类如何访问WEB资源的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2018-04-04
  • Java+opencv3.2.0之直方图均衡详解

    Java+opencv3.2.0之直方图均衡详解

    这篇文章主要为大家详细介绍了Java+opencv3.2.0之直方图均衡的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02

最新评论