内存溢出?

https://www.cnblogs.com/crossoverJie/p/9552119.html

前言
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 出当前应用的内存情况。

结果发现 com.lmax.disruptor.RingBuffer 类型的对象占用了将近 50% 的内存。

看到这个包自然就想到了 Disruptor 环形队列。

再次 review 代码发现:从 Kafka 里取出的 700 条数据是直接往 Disruptor 里丢的。

这里也就能说明为什么第一次模拟数据没复现问题了。

模拟的时候是一个对象放进队列里,而生产的情况是 700 条数据放进队列里。这个数据量是 700 倍的差距。

而 Disruptor 作为一个环形队列,再对象没有被覆盖之前是一直存在的。

我也做了一个实验,证明确实如此。

我设置队列大小为 8 ,从 0~9 往里面写 10 条数据,当写到 8 的时候就会把之前 0 的位置覆盖掉,后面的以此类推(类似于 HashMap 的取模定位)。

所以在生产上假设我们的队列大小是 1024,那么随着系统的运行最终肯定会导致 1024 个位置上装满了对象,而且每个位置是 700 个!

于是查看了生产上 Disruptor 的 RingBuffer 配置,结果是:1024*1024。

这个数量级就非常吓人了。

为了验证是否是这个问题,我在本地将该值换为 2 ,一个最小值试试。

同样的 128M 内存,也是通过 Kafka 一直源源不断的取出数据。通过监控如下:

跑了 20 几分钟系统一切正常,每当一次 GC 都能回收大部分内存,最终呈现锯齿状。

这样问题就找到了,不过生产上这个值具体设置多少还得根据业务情况测试才能知道,但原有的 1024*1024 是绝对不能再使用了。

总结
虽然到了最后也就改了一行代码(还没改,直接修改配置),但这排查过程我觉得是有意义的。

也会让大部分觉得 JVM 这样的黑盒难以下手的同学有一个直观的感受。

同时也得感叹 Disruptor 东西虽好,也不能乱用哦!

相关演示代码查看:

https://github.com/crossoverJie/JCSprout/tree/master/src/main/java/com/crossoverjie/disruptor

你的点赞与转发是最大的支持。

Java内存溢出?的更多相关文章

  1. Java 内存溢出(java.lang.OutOfMemoryError)的常见情况和处理方式总结

    最近老是遇见服务器内存溢出的问题,故在网上搜了搜,总结了一些java内存溢出的解决方式 java.lang.OutOfMemoryError这个错误我相信大部分开发人员都有遇到过,产生该错误的原因大都 ...

  2. java内存溢出分析(二)

    我们继续java内存溢出分析(一)的分析,点击Details>按钮,显示如下图,我们发现有一个对象数量达到280370216个,再点击其中的List objects 点击后,显示下图 至此,我们 ...

  3. Java内存溢出详解

    转自:http://elf8848.iteye.com/blog/378805 一.常见的Java内存溢出有以下三种: 1. java.lang.OutOfMemoryError: Java heap ...

  4. Java内存溢出的详细解决方案

    本文介绍了Java内存溢出的详细解决方案.本文总结内存溢出主要有两种情况,而JVM经常调用垃圾回收器解决内存堆不足的问题,但是有时仍会有内存不足的错误.作者分析了JVM内存区域组成及JVM设置虚拟内存 ...

  5. 老李案例分享:定位JAVA内存溢出

    老李案例分享:定位JAVA内存溢出   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.在poptest的loadrunner的培 ...

  6. java内存溢出问题

    相信有一定java开发经验的人或多或少都会遇到OutOfMemoryError的问题,这个问题曾困扰了我很长时间,随着解决各类问题经验的积累以及对问题根源的探索,终于有了一个比较深入的认识. 在解决j ...

  7. Java内存溢出异常(上)

    上一篇文章我们讲了JVM运行时数据区域与内存溢出异常,其中对于内存溢出异常这部分将的不够详细,这篇文章将着重讲解Java内存溢出异常的相关知识.如果有没看过上一篇文章的小伙伴们,请点击Java内存区域 ...

  8. Java内存溢出异常(下)

    此篇是上一篇文章Java内存溢出异常(上)的续篇,没有看过的同学,可以先看一下上篇.本篇文章将介绍剩余的两个溢出异常:方法区和运行时常量池溢出. 方法区和运行时常量池溢出 这部分为什么会放在一起呢?在 ...

  9. java内存溢出的解决思路

    原文地址:https://www.cnblogs.com/200911/p/3965108.html 内存溢出是指应用系统中存在无法回收的内存或使用的内存过多,最终使得程序运行要用到的内存大于虚拟机能 ...

  10. java内存溢出分析工具

    http://www.cnblogs.com/preftest/archive/2011/12/08/2281322.html java内存溢出分析工具:jmap使用实战 在一次解决系统tomcat老 ...

随机推荐

  1. hdu 4587 2013南京邀请赛B题/ / 求割点后连通分量数变形。

    题意:求一个无向图的,去掉两个不同的点后最多有几个连通分量. 思路:枚举每个点,假设去掉该点,然后对图求割点后连通分量数,更新最大的即可.算法相对简单,但是注意几个细节: 1:原图可能不连通. 2:有 ...

  2. WEB学习-基础知识:列表、表单、div和span、注释、字符实体、HTML废弃标签介绍

    列表 无序列表 无序列表,用来表示一个列表的语义,并且每个项目和每个项目之间,是不分先后的. ul就是英语unordered list,“无序列表”的意思. li 就是英语list item , “列 ...

  3. NOIP临考经验(转)

    [COGS]NOIP临考经验 1.  提前15分钟入场,此时静坐调整心态,适当的深呼吸 2.  打开编辑器并调整为自己喜欢的界面 3.  熟悉文件目录,写好准确无误的代码模板 4.  压缩包或许还不能 ...

  4. Linux下xz与tar的区别

    同一文件,tar.xz格式比tar.gz格式小了三分之一! 说明: xz是一个使用LZMA压缩算法的无损数据压缩文件格式. 和gzip与bzip2一样,同样支持多文件压缩,但是约定不能将多于一个的目标 ...

  5. gcc、arm-Linux-gcc和arm-elf-gcc的组成及区别

    2017-01-19 嵌入式ARM 嵌入式ARM 一.GCC简介 The GNU Compiler Collection,通常简称 GCC,是一套由 GNU 开发的编译器集,为什么是编辑器集而不是编译 ...

  6. Chrome/谷歌开发者工具分析

    Chrome/谷歌开发者工具还是要好好掌握一下,对于前端开发超级有用:https://developers.google.com/web/tools/chrome-devtools/ 1.js内存使用 ...

  7. outlook 2010 自动密送Email

    以下功能请勿非法使用: 密抄到多人这个需要用到宏 方法一: 1.在Outlook里面键入ALT+F11打开VBA编辑器 2.展开“Project (VbaProject.OTM)/Microsoft ...

  8. Intel Edision —— 上电、基本设置与系统初探

    前言 原创文章,转载引用务必注明链接.如有疏漏,欢迎斧正. Intel的文档其实挺清楚了,坛子上很多人把文档又详细复述一边,私以为一篇就够了其他的跟着文档走一遍也挺好的...俗一把使用过程顺手记录下来 ...

  9. pomelo加入定时任务

    需求:在arenaserver下添加一个rank定时任务,每一分钟对对玩家进行一次排行. 首先在game-server/app/servers/arena文件夹下添加cron文件夹. 在game-se ...

  10. SpringBoot学习之文件结构和配置文件

    Springboot文件结构和配置文件 转载:http://www.zslin.com/web/article/detail/11 项目文件结构 新建的Springboot项目的文件结构如下: |-c ...