[转帖]Cat导致内存不足原因分析
背景
线上几亿的数据在回刷的时候容器服务会出现OOM而重启,导致任务中断
内存泄露分析
jmap -histo pid 找出了有几十亿的java.lang.StackTraceElement对象,找不到被谁引用了
jmap -dump:format=b,file=heapdump.hprof pid dump内存
下载到本机mac上,用mat(MemoryAnalyzer)分析,得到内存泄露报告,看到内存全部被com.dianping.cat.message.internal.DefaultMessageManager$Context引用,找到了罪魁祸首

原因分析
com.dianping.cat.log4j.Log4j2Appender 在打印错误Exception的时候会调用Cat.logError方法
public class Log4j2Appender extends AbstractAppender {
....
public void append(LogEvent event) {
try {
Level level = event.getLevel();
if (level.isMoreSpecificThan(Level.WARN)) {
this.logError(event);
}
} catch (Exception var3) {
if (!this.ignoreExceptions()) {
throw new AppenderLoggingException(var3);
}
}
}
....
private void logError(LogEvent event) {
Throwable exception = event.getThrown();
if (exception != null) {
Message message = event.getMessage();
if (message != null) {
Cat.logError(message.getFormattedMessage(), exception);
} else {
Cat.logError(exception);
}
}
<span class="token punctuation">}</span>
}
Cat类的logError函数最终调用到了DefaultMessageManager.shouldLog方法
public class Cat {
...
public static void logError(String message, Throwable cause) {
try {
getProducer().logError(message, cause);
} catch (Exception var3) {
errorHandler(var3);
}
<span class="token punctuation">}</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">logError</span><span class="token punctuation">(</span><span class="token class-name">Throwable</span> cause<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">try</span> <span class="token punctuation">{<!-- --></span>
<span class="token function">getProducer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">logError</span><span class="token punctuation">(</span>cause<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> var2<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token function">errorHandler</span><span class="token punctuation">(</span>var2<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
public class DefaultMessageProducer implements MessageProducer {
public void logError(String message, Throwable cause) {
if (Cat.getManager().isCatEnabled()) {
if (this.shouldLog(cause)) {
....
}
} else {
cause.printStackTrace();
}
}
private boolean shouldLog(Throwable e) {
return this.m_manager instanceof DefaultMessageManager ? ((DefaultMessageManager)this.m_manager).shouldLog(e) : true;
}
DefaultMessageManager类的m_context在shouldLog的时候把异常堆栈保存下来了,如果Cat事务不关闭,随着异常越来越多就导致了内存溢出
public class DefaultMessageManager {
private ThreadLocal<DefaultMessageManager.Context> m_context = new ThreadLocal();
boolean shouldLog(Throwable e) {
DefaultMessageManager.Context ctx = (DefaultMessageManager.Context)this.m_context.get();
return ctx != null ? ctx.shouldLog(e) : true;
}
<span class="token keyword">class</span> <span class="token class-name">Context</span> <span class="token punctuation">{<!-- --></span>
<span class="token comment">// 内存不足就是由于错误堆栈信息没有限制导致的</span>
<span class="token keyword">private</span> <span class="token class-name">Set</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">Throwable</span><span class="token punctuation">></span></span> m_knownExceptions<span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token class-name">Context</span><span class="token punctuation">(</span><span class="token class-name">String</span> domain<span class="token punctuation">,</span> <span class="token class-name">String</span> hostName<span class="token punctuation">,</span> <span class="token class-name">String</span> ipAddress<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>m_knownExceptions <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">shouldLog</span><span class="token punctuation">(</span><span class="token class-name">Throwable</span> e<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>m_knownExceptions <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">this</span><span class="token punctuation">.</span>m_knownExceptions <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HashSet</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>m_knownExceptions<span class="token punctuation">.</span><span class="token function">contains</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
<span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{<!-- --></span>
<span class="token comment">// 这里没有限制大小,只要有异常就往Set里面添加,这里应该做一个优化</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>m_knownExceptions<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>e<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
}
解决方案
手动调用Cat.getManager().reset();方法清空保存的异常堆栈信息
public void reset() {
DefaultMessageManager.Context ctx = (DefaultMessageManager.Context)this.m_context.get();
if (ctx != null) {
if (ctx.m_totalDurationInMicros == 0L) {
ctx.m_stack.clear();
ctx.m_knownExceptions.clear();
this.m_context.remove();
} else {
// 这里会释放错误日志堆栈信息
ctx.m_knownExceptions.clear();
}
}
}
[转帖]Cat导致内存不足原因分析的更多相关文章
- tomcat 内存溢出原因分析及解决
一.错误提示:java.lang.OutOfMemoryError: Java heap space [原因分析] tomcat默认可以使用内存为128MB,在较大型的应用项目中不足以满足运行要求,在 ...
- Android 非静态内部类导致内存泄漏原因深入剖析
背景 上周发现蘑菇街IM-Android代码里面.一些地方代码编写不当.存在内存泄漏的问题.在和疯紫交流的过程中.发现加深了一些理解,所以决定写一下分析思路,相互学习. 内存泄漏 一个不会被使用的对象 ...
- Activity内部Handler引起内存泄露的原因分析
有时在Activity中使用Handler时会提示一个内存泄漏的警告,代码通常如下: public class MainActivity extends Activity { private Text ...
- Spark集群无法停止的原因分析和解决
今天想停止spark集群,发现执行stop-all.sh的时候spark的相关进程都无法停止.提示: no org.apache.spark.deploy.master.Master to stop ...
- drawRect导致内存暴增的真正原因
那么现在我们分析一下drawRect导致内存暴增的真正原因: 重写drawRect为何会导致内存大量上涨? 要想搞明白这个问题,我们需要撸一撸在 iOS 程序上图形显示的原理.在 iOS 系统中所有显 ...
- iOS学习——内存泄漏检查及原因分析
项目的代码很多,前两天老大突然跟我说项目中某一个ViewController的dealloc()方法没有被调用,存在内存泄漏问题,需要排查原因,解决内存泄漏问题.由于刚加入项目组不久,对出问题的模块的 ...
- .Net线程池ThreadPool导致内存高的问题分析
最近写了一个WinFrom程序.此程序侦听TCP端口,接受消息处理,然后再把处理后的消息,利用线程池通过WebService发送出去(即一进一出). 在程序编写完成后,进行压力测试.用Fiddler提 ...
- 关于JVM内存溢出的原因分析及解决方案探讨
前言:JVM中除了程序计数器,其他的区域都有可能会发生内存溢出. 0.什么是内存溢出 当程序需要申请内存的时候,由于没有足够的内存,此时就会抛出OutOfMemoryError,这就是内存溢出. 1. ...
- ThreadLocal内存溢出代码演示和原因分析!
ThreadLocal 翻译成中文是线程本地变量的意思,也就是说它是线程中的私有变量,每个线程只能操作自己的私有变量,所以不会造成线程不安全的问题. 线程不安全是指,多个线程在同一时刻对同一个全局 ...
- 添加IFrame导致内存溢出的解决过程(IE浏览器,目前发现了原因,还未解决)
1. 现象 每次动态添加iframe时,iexplore.exe进程占据的内存都会增加(大概10M左右),不会自动释放,最终导致内存溢出 2. 解决过程 经过网络的一番搜索,基本上给出的解决方案是 ...
随机推荐
- Java 在PPT中添加文本、图片超链接
本文介绍通过Java程序在PPT幻灯片中添加超链接的方法,可以给文本或者图片设置超链接,设置超链接时,可设置包括网页链接.邮件地址链接.幻灯片跳转链接等不同指向对象的链接.文中方法使用了免费版PPT类 ...
- JavaScript回调函数的高手指南
摘要:本文将会解释回调函数的概念,同时帮你区分两种回调:同步和异步. 回调函数是每个前端程序员都应该知道的概念之一.回调可用于数组.计时器函数.promise.事件处理中. 本文将会解释回调函数的概念 ...
- DevSecOps“内置安全保护”,让软件研发“天生健康”
摘要:我们主要是围绕安全架构设计保证安全落地有法可依,进行威胁建模让安全落地有迹可循.做好隐私和敏感数据保护让安全落地在每一个细节和实处这几个方面进行阐述. 本文分享自华为云社区<DevSecO ...
- WebKit三件套(2):WebKit之JavaScriptCore/V8
WebKit作为一个浏览器引擎,其中Javascript实现包括JavaScriptCore和V8,为了能更全面的了解WebKit,我们需要深入的了解Javascript实现的基本原理.其在WebKi ...
- 资源成本降低60%!火山引擎ByteHouse助力数字营销平台仟传网络降本增效
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 近日,中国知名内容社交平台整合营销企业仟传网络与火山引擎ByteHouse达成合作.仟传网络将通过火山引擎By ...
- Python 太难懂?火山引擎数智平台这款产品可以了解一下!
更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 「自学 Python?一般人我还是劝你算了吧!」 在国内知识分享平台「知乎」上,这一吐槽话题获得了超过 260 ...
- WPF 自定义可拖动标题栏
要注意,拖拽的地方,需要加背景色,否则 DrageMove 将无效 MainWindows.xaml <Window x:Class="Report.MainWindow" ...
- .Net Core NLog 配置
using NLog; private static Logger logger = LogManager.GetCurrentClassLogger(); //初始化日志类 NLog.config ...
- Java 项目工程搭建 --创建子模块(Spring Initializr)
一下篇,常用 Java 项目工程搭建 --创建子模块(依赖父工程) 也不算常用,常用的是 ctrl+c.ctrl+v ,哈哈 Package要手动改下,生成的很丑 选能支持 Alibaba Cl ...
- OS | 读者写者问题(读者优先,写者优先 ,读写公平)
读者优先 读者优先的解决方案: 互斥信号量 wrt,初值是 \(1\),代表一个共享文件,解决 "读-写"互斥,"写-写"互斥. 一个记数器,即整型变量 rea ...