强如 Disruptor 也发生内存溢出?(上)

简介: OutOfMemoryError 问题相信很多朋友都遇到过,相对于常见的业务异常(数组越界、空指针等)来说这类问题是很难定位和解决的。本文以最近碰到的一次线上内存溢出的定位、解决问题的方式展开;希望能对碰到类似问题的同学带来思路和帮助。主要从表现-->排查-->定位-->解决 四个步骤来分析和解决问题。

表象


最近我们生产上的一个应用不断的爆出内存溢出,并且随着业务量的增长出现的频次越来越高。


该程序的业务逻辑非常简单,就是从 Kafka 中将数据消费下来然后批量的做持久化操作。


而现象则是随着 Kafka 的消息越多,出现的异常的频次就越快。由于当时还有其他工作所以只能让运维做重启,并且监控好堆内存以及 GC 情况。


重启大法虽好,可是依然不能根本解决问题。


排查


于是我们想根据运维之前收集到的内存数据、GC 日志尝试判断哪里出现问题。



结果发现老年代的内存使用就算是发生 GC 也一直居高不下,而且随着时间推移也越来越高。


结合 jstat 的日志发现就算是发生了 FGC 老年代也已经回收不了,内存已经到顶。



甚至有几台应用 FGC 达到了上百次,时间也高的可怕。


这说明应用的内存使用肯定是有问题的,有许多赖皮对象始终回收不掉。


定位


由于生产上的内存 dump 文件非常大,达到了几十G。也是由于我们的内存设置太大有关。


所以导致想使用 MAT 分析需要花费大量时间。


因此我们便想是否可以在本地复现,这样就要好定位的多。


为了尽快的复现问题,我将本地应用最大堆内存设置为 150M。


然后在消费 Kafka 那里 Mock 为一个 while 循环一直不断的生成数据。


同时当应用启动之后利用 VisualVM 连上应用实时监控内存、GC 的使用情况。


结果跑了 10 几分钟内存使用并没有什么问题。根据图中可以看出,每产生一次 GC 内存都能有效的回收,所以这样并没有复现问题。



没法复现问题就很难定位了。于是我们 review 代码,发现生产的逻辑和我们用 while 循环 Mock 数据还不太一样。


查看生产的日志发现每次从 Kafka 中取出的都是几百条数据,而我们 Mock 时每次只能产生一条


为了尽可能的模拟生产情况便在服务器上跑着一个生产者程序,一直源源不断的向 Kafka 中发送数据。


果然不出意外只跑了一分多钟内存就顶不住了,观察左图发现 GC 的频次非常高,但是内存的回收却是相形见拙。



同时后台也开始打印内存溢出了,这样便复现出问题。


解决


从目前的表现来看就是内存中有许多对象一直存在强引用关系导致得不到回收。


于是便想看看到底是什么对象占用了这么多的内存,利用 VisualVM 的 HeapDump 功能可以立即 dump 出当前应用的内存情况。



相关文章
|
消息中间件 监控 Java
强如 Disruptor 也发生内存溢出?(下)
OutOfMemoryError 问题相信很多朋友都遇到过,相对于常见的业务异常(数组越界、空指针等)来说这类问题是很难定位和解决的。 本文以最近碰到的一次线上内存溢出的定位、解决问题的方式展开;希望能对碰到类似问题的同学带来思路和帮助。 主要从表现-->排查-->定位-->解决 四个步骤来分析和解决问题。
|
Java
Disruptor 全解析(7):解密内存屏障(Memory Barrier)
原文地址:http://mechanitis.blogspot.com/2011/08/dissecting-disruptor-why-its-so-fast.html​​, 作者是 Trisha Gee, LMAX 公司的一位女工程师。
2541 0
|
26天前
|
缓存 Prometheus 监控
Elasticsearch集群JVM调优设置合适的堆内存大小
Elasticsearch集群JVM调优设置合适的堆内存大小
208 1
|
15天前
|
存储 监控 算法
深入探索Java虚拟机(JVM)的内存管理机制
本文旨在为读者提供对Java虚拟机(JVM)内存管理机制的深入理解。通过详细解析JVM的内存结构、垃圾回收算法以及性能优化策略,本文不仅揭示了Java程序高效运行背后的原理,还为开发者提供了优化应用程序性能的实用技巧。不同于常规摘要仅概述文章大意,本文摘要将简要介绍JVM内存管理的关键点,为读者提供一个清晰的学习路线图。
|
24天前
|
Java
JVM内存参数
-Xmx[]:堆空间最大内存 -Xms[]:堆空间最小内存,一般设置成跟堆空间最大内存一样的 -Xmn[]:新生代的最大内存 -xx[use 垃圾回收器名称]:指定垃圾回收器 -xss:设置单个线程栈大小 一般设堆空间为最大可用物理地址的百分之80
|
25天前
|
Java
JVM运行时数据区(内存结构)
1)虚拟机栈:每次调用方法都会在虚拟机栈中产生一个栈帧,每个栈帧中都有方法的参数、局部变量、方法出口等信息,方法执行完毕后释放栈帧 (2)本地方法栈:为native修饰的本地方法提供的空间,在HotSpot中与虚拟机合二为一 (3)程序计数器:保存指令执行的地址,方便线程切回后能继续执行代码
19 3
|
26天前
|
存储 缓存 监控
Elasticsearch集群JVM调优堆外内存
Elasticsearch集群JVM调优堆外内存
45 1