最近一个服务突然出现 OutOfMemoryError,两台服务因为这个原因挂掉了,一直在full gc。还因为这个问题我们小组吃了一个线上故障。很是纳闷,一直运行的好好的,怎么突然就不行了呢。。。
配置了一个  -XX:+HeapDumpOnOutOfMemoryError(该参数作用是在第一次发生OOM错误时候会打印dump内存信息),便开始通过dump文件开始查找问题。
 

项目各项环境参数:

项目使用dubbo框架,dubbo线程池配置500
项目内存配置2G,old区1.5G
项目使用   Log4j + Disruptor 实现的异步记录日志
log4j-api版本2.6.2            log4j-core版本2.6.2
disruptor版本3.3.6
 
 

问题分析:

都知道发生OOM问题是因为内存不够,造成原因却有很多。具体的场景具体分析,通过gc日志发现每次full gc回收的内存越来越少,造成最后OutOfMemoryError: GC overhead limit exceeded。
通过Java MAT工具分析dump发现,一个最大dubbo线程占用内存12M,总的dubbo线程占用内存加起来都已经1.6G了。
 
 
为什么一个dubbo线程会占用这个大的内存呢,很是奇怪,节点打开一个具体线程信息看到,
 
 
一个dubbo线程是有一个threadlocal对象,threadlocal对象里面引用了一个java StringBuilder对象,改对象有char数组6百多万,占用内存12M。
通过ThreadLocalMap$Entry对象里referent属性找到引用ThreadLocal对象:
 
 
看到这里,觉得有点希望了,继续打开代码搜索log4j中ParameterizedMessage类,看到里面有一行代码:
    // storing JDK classes in ThreadLocals does not cause memory leaks in web apps, so this is okay
    private static ThreadLocal<StringBuilder> threadLocalStringBuilder = new ThreadLocal<>();
这个StringBuilder不就是上面看到打对象吗,知道了这个对象,接下来就是看这个ThreadLocal是怎么使用的啦。
继续查看log4j + Disurptor源码。。。
发现在打日志代码中,RingBufferLogEvent中setMessage方法会进行打印日志的一个格式化,
 
 
继续跟进去,看看格式化具体做了什么即 ParameterizedMessage.getFormattedmessage()方法
 
 
问题就出在这个方法里,方法是从当前线程ThreadLocal里面拿到StringBuilder对象,然后每次将length置0,然后将日志append进去
所以从这里就知道,只要有一次日志内容打印很多情况下,会造成StringBuilder里字段串对象很大,而且是不会销毁(除非当前ThreadLocal线程死了,前面说了项目配置了dubbo 500个线程,dubbo线程不死,所以这个对象一直都在),打印大日志对象次数多了,基本上造成所有dubbo线程ThreadLocal StringBuilder对象都很大。正如第一幅图看到一样,最终造成OOM。
 
 
log4j 2.6.2这里进行日志格式化,打印日志内容过大时候确实会造成这个问题
然后拉取了下log4j新一些的,发现在log4j 在2.9.0版本解决了这个问题,如何解决的呢,具体来看看代码吧,还是ParameterizedMessage.getFormattedmessage()这个方法:
 
发现只多了一行代码,继续看:
 
这里回判断如果stringbuilder不为null并且容量大于maxSize(这个参数可配,默认518),会将长度置为maxSize,然后调用trimToSize方法,
 
刚方法就是将原char数组进行了一次copy,copy了一个maxSize大小的数组。
这样即就是每次格式化之后会进行一次判断,如果对象ThreadLocal stringbuilder对象太大会将该对象重新copy一个固定大小,避免老版本出现OOM问题。
 
 

记一次log4j日志导致线上OOM问题案例的更多相关文章

  1. 记一次ArrayList产生的线上OOM问题

    前言:本以为(OutOfMemoryError)OOM问题会离我们很远,但在一次生产上线灰度的过程中就出现了Java.Lang.OutOfMemoryError:Java heap space异常,通 ...

  2. nmap扫描端口导致线上大量Java服务FullGC甚至OOM

    nmap扫描端口导致线上大量Java服务FullGC甚至OOM 最近公司遇到了一次诡异的线上FullGC保障,多个服务几乎所有的实例集中报FullGC,个别实例甚至出现了OOM,直接被docker杀掉 ...

  3. 一次线上OOM故障排查经过

    转贴:http://my.oschina.net/flashsword/blog/205266 本文是一次线上OOM故障排查的经过,内容比较基础但是真实,主要是记录一下,没有OOM排查经验的同学也可以 ...

  4. 火山引擎MARS-APM Plus x 飞书 |降低线上OOM,提高App性能稳定性

    通过使用火山引擎MARS-APM Plus的memory graph功能,飞书研发团队有效分析定位问题线上case多达30例,线上OOM率降低到了0.8‰,降幅达到60%.大幅提升了用户体验,为飞书的 ...

  5. 【转】又一次线上 OOM 排查经过

    又一次线上OOM排查经过 最近线上一个服务又出现了频繁Full GC的情况,导致提供的业务经常超时.问题出现非常不稳定,经过两周的时候,终于又捕捉到了一次Full GC,于是联系运维做Heap Dum ...

  6. 记一次令人窒息的线上fullgc调优

    今天第二篇采坑了... ... 现场因为处理太急促没有保留,而且是一旁协助,没有收集到所有信息实在是有些遗憾...只能靠记忆回想一些细节 情况是一台服务器一启动就开始full gc,短短1分钟可以有几 ...

  7. 关于GC(上):Apache的POI组件导致线上频繁FullGC问题排查及处理全过程

    某线上应用在进行查询结果导出Excel时,大概率出现持续的FullGC.解决这个问题时,记录了一下整个的流程,也可以作为一般性的FullGC问题排查指导. 1. 生成dump文件 为了定位FullGC ...

  8. 记一次线上 OOM 和性能优化

    大家好,我是鸭血粉丝(大家会亲切的喊我 「阿粉」),是一位喜欢吃鸭血粉丝的程序员,回想起之前线上出现 OOM 的场景,毕竟当时是第一次遇到这么 紧脏 的大事,要好好记录下来. 1 事情回顾 在某次周五 ...

  9. 记一次线上OOM问题分析与解决

    一.问题情况 最近用户反映系统响应越来越慢,而且不是偶发性的慢.根据后台日志,可以看到系统已经有oom现象. 根据jdk自带的jconsole工具,可以监视到系统处于堵塞时期.cup占满,活动线程数持 ...

随机推荐

  1. C#装饰者模式实例代码

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace 装饰者 ...

  2. 利用js动态创建<style>

    var nod = document.createElement(“style”), str = “body{background:#000;color:#fff} a{color:#fff;text ...

  3. 【Python】《大话设计模式》Python版代码实现

    <大话设计模式>Python版代码实现 上一周把<大话设计模式>看完了,对面向对象技术有了新的理解,对于一个在C下写代码比较多.偶尔会用到一些脚本语言写脚本的人来说,很是开阔眼 ...

  4. 初始小R-安装启动与测试

    非常感谢<深入浅出数据分析>这本书让我有幸认识了R,多多少少的弥补了我心里对R语言.R分析.R工具的模糊认知,下面我们就来体验一下R语言的魅力吧!GO! 一:下载R R官方地址:http: ...

  5. angularjs中的ng-src和ng-href

    ng-src和ng-href等同于html中的src和href,只是ng是在dom加载完毕之后才能够发挥作用,如果在src或href中绑定变量,如果ng没有加载完,会导致链接地址出错,如果用对应的ng ...

  6. Java程序实现密钥库的维护

    1 Java程序列出密钥库所有条目 import java.util.*; import java.io.*; import java.security.*; public class ShowAli ...

  7. 算法笔记_018:旅行商问题(Java)

    目录 1 问题描述 2 解决方案 2.1 蛮力法 2.2 减治法 2.2.1 Johson-Trotter算法 2.2.2 基于字典序的算法   1 问题描述 何为旅行商问题?按照非专业的说法,这个问 ...

  8. Android SDK镜像的介绍使用【转发】

    由于一些原因,Google相关很多服务都无法访问,所以在很多时候我们SDK也无法升级,当然通过技术手段肯定可以解决,但是比较麻烦,而且下载速度也不怎么样. 这里笔者介绍一个国内的Android镜像站, ...

  9. excel 如何为列添加指定内容(字符串)

      excel 如何为列添加指定内容(字符串) CreateTime--2018年5月26日17:52:32 Author:Marydon 1.情景展示 D列的值需要获取B列的值并且在后面统一加上12 ...

  10. Git高速入门——Git安装、创建版本号库以及经常使用命令

    学习Git最全面的资料,在我看来是这本书--Pro Git,网上关于Git的教程有非常多,包含当中一些非常优秀的教程.这一系列的博客,主要是记录自己学习Git的经历.以及在这一过程中遇到的一些问题. ...