• 上Mysql com.mysql.jdbc.StatementImpl$CancelTask内存泄漏问题和解决方法


    近来在负责公司短信网关的维护及建设,随着公司业务发展对短信依赖越来越严重了,短信每天发送量也比曾经每天40多w发送量暴增到每天达到200w发送量。由于是採用Java做发送底层,压力递增情况下不可避免的面对内存问题。

    在发送量接近200w情况下,出现内存泄露问题了。

    经过对系统执行检查发现:

            1)每次重新启动系统3-4个小时后。均发现一点不稳定;

            2)在3-4个小时后。出现out of memory的错误:java.lang.OutOfMemoryError: GC overhead limit exceeded

    发现这个问题后,直接通过JMS获取监控日志,发现系统的内存回收存在异常,gc压力很大并且存在明显内存积压。




    然后直接把系统的内存down下来分析,发现的确存在内存积压情况:


    这个是mysql的一个定时任务的,这个定时任务主要作用是在用于做查询超时的。

    简单举个样例,系统在运行一个sql查询情况下。jdbc会给你一个超时时间。为了保证超时时间后,能够关闭statement,会打开一个保护关闭的定时任务。假设超时情况下,sql还没响应运行,cancel task就会运行关闭任务。由于c3p0的默认设置的超时时间为25s(<setting name="defaultStatementTimeout" value="25000" />),意味这个25s内,在运行大量sql情况下。cancel task积压到了一定程度,就会造成系统不稳定。

    (最后发现这个并非根本原因,仅仅是表象)

    可是系统本身就有通过mysql做发送队列的,本身对mysql操作许多。假设仅仅是对代码层面下优化基本杯水车薪。

    在时间紧迫的情况下。短时间内稳定业务才是最重要的任务。

    被逼依据以上现状採用了暂时方案解决。


    暂时方案

            通过以上推断,基本能够判定cancel task在某组线程执行应该会形成一个峰值,撑爆了JVM的堆。可是如今无法在停止业务执行做过多调试,所以当机立断,对JVM的内存扩大一倍以上,希望系统能够跨过一波内存峰值。结果把JVM的内存调整为故障时候的2倍时候,系统的内存又恢复到正常运作。只是cancel task最高值会占用到内存2G以上。尽管也是会回收,可是一直扩内存不是非常好的办法。


    解决方式

    系统採用的mysql jdbc 5.1.6的版本号,立马反编译mysql代码,发现下面问题。

    由于cancel task的timer在connection中静态存放。意味statement假设正常查询出结构,业务无法把cancel task内存回收才是故障根本原因。


    明白问题在mysql jdbc上面后。根本解决的方法应该查询mysql jdbc是否攻克了这个bug。

    在5.1.11版本号中找到这个bug的修复。更新后。内存泄漏故障得到解决。http://dev.mysql.com/doc/relnotes/connector-j/en/news-5-1-11.html


    讨论并协助谢国波感和锐利康。使故障得以圆满解决!

  • 相关阅读:
    JAVA 实现json diff
    Apache httpclient拦截器对请求进行签名
    okHttp3教程:5种基本请求示例,拦截器实现自动重试和日志打印
    代码执行testng的几种方式
    封装log4j支持记录到testng
    修改ZuulHandlerMapping私有变量pathMatcher,重写match方法,使url匹配兼容正则表达式。
    修改testng源码,添加beforeMethod和afterMethod中的日志到test中(可以不改源码,废弃)
    Linux Python import jenkins 报错 oserror: /usr/lib/python2.7/site-packages/lookup3.so
    mongodb相关查询
    monkey命令参数介绍
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/5038370.html
Copyright © 2020-2023  润新知