upcgg

导航

 

某方法,在50用户并发时,执行4分钟,TPS下降,堆内存的老年代占用100%,并频繁执行fullGC,单个实例占用堆内存94%。

 

 

该问题的根本原因:

频繁FULL GC 是项目使用的mysql jdbc driver版本低(5.1.5),这个版本有bug. https://bugs.mysql.com/bug.php?id=36565 .

解决办法:

  1. 方法一  (推荐): 升级mysql jdbc driver 到更新的版本(5.1.11以上),比如5.1.18, 或
  2. 方法二:修改mybatis的配置文件,不设置queryTimeout时间,比如,从jd-treasure-dao项目中的mybatis-config.xml文件中去掉下面的设置
<!-- 设置超时时间,它决定驱动等待一个数据库响应的时间 -->
<setting name="defaultStatementTimeout" value="600"/>

其他有些业务线也使用了5.1.5版本,但因为没有设置defaultStatementTimeout,所以没有出现该问题。

分析过程:

 1.通过dump文件,看到有大量的CancelTask 对象(928606个),应该是GC不掉

 

  1. 查看driver 5.1.5 的源代码    StatementImpl.java

public boolean execute(String sql) throws SQLException {

if (locallyScopedConn.getEnableQueryTimeouts() &&
        this.timeoutInMillis != 0
        && locallyScopedConn.versionMeetsMinimum(5, 0, 0)) {
    timeoutTask = new CancelTask(this);
    ConnectionImpl.getCancelTimer().schedule(timeoutTask,
            this.timeoutInMillis);
}

}

该类里还有executeQuery等几个方法都使用到了CancelTask.   其中CancelTimer是ConnectionImpl里的一个静态变量,不会被GCed.  造成每次进行SQL操作新生成的cancelTask对象不会被GCed.  timeoutInMillis 在一元夺宝项目里是通过mybatis-config.xml文件的defaultStatementTimeout设置的。

posted on 2016-02-17 14:39  upcgg  阅读(2593)  评论(0编辑  收藏  举报