内存溢出分析

timer每隔1天时间就会outofMemory一次,,,,,很恼火,,,,

思路:

第一步:必须拿到heapdump文件,,,

  在jvm启动参数加上  -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=日志路径,这样在下次outofmemory的时候  可以生成heapdump文件


第二步: 分析heapdump文件

  

发现ibatis缓存有大量数据,,,,,,可以从缓存里面看到是哪一条sql的数据


 从ibatis缓存的key可以了解到是哪个sql导致的,,,,,, 


但是问题来了,,,,为什么ibatis有这么多缓存没有释放,这些缓存缓存的内容都是同一条查询,只是limit不同而已。

所以需要通过源码找到ibatis缓存释放的代码,,,,,,

发现是在SqlSessionTemplate 里面(公司的ibatis是跟spring集成的)

sqlSession的操作其实是通过代理实现的,,,,

public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType,
      PersistenceExceptionTranslator exceptionTranslator) {


    notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
    notNull(executorType, "Property 'executorType' is required");


    this.sqlSessionFactory = sqlSessionFactory;
    this.executorType = executorType;
    this.exceptionTranslator = exceptionTranslator;
    this.sqlSessionProxy = (SqlSession) newProxyInstance(
        SqlSessionFactory.class.getClassLoader(),
        new Class[] { SqlSession.class },
        new SqlSessionInterceptor());
  }

看看代理的代码

 private class SqlSessionInterceptor implements InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      final SqlSession sqlSession = getSqlSession(
          SqlSessionTemplate.this.sqlSessionFactory,
          SqlSessionTemplate.this.executorType,
          SqlSessionTemplate.this.exceptionTranslator);
      try {
        Object result = method.invoke(sqlSession, args);
        if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
          // force commit even on non-dirty sessions because some databases require
          // a commit/rollback before calling close()
          sqlSession.commit(true);
        }
        return result;
      } catch (Throwable t) {
        Throwable unwrapped = unwrapThrowable(t);
        if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
          Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
          if (translated != null) {
            unwrapped = translated;
          }
        }
        throw unwrapped;
      } finally {
        closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
      }
    }
  }


public static void closeSqlSession(SqlSession session, SqlSessionFactory sessionFactory) {


    notNull(session, "No SqlSession specified");
    notNull(sessionFactory, "No SqlSessionFactory specified");


    SqlSessionHolder holder = (SqlSessionHolder) getResource(sessionFactory);
    if ((holder != null) && (holder.getSqlSession() == session)) {//如果使用spring事务,,,会在事务结束后统一释放缓存内存。如果事务没有结束缓存是不会释放的
      if (logger.isDebugEnabled()) {
        logger.debug("Releasing transactional SqlSession [" + session + "]");
      }
      holder.released();
    } else {//如果没有使用spring事务,,,每一次sqlSession操作结束后 立马释放缓存
      if (logger.isDebugEnabled()) {
        logger.debug("Closing non transactional SqlSession [" + session + "]");
      }
      session.close();
    }
  }


通过以上分析,,,问题大概找到了,,,某个地方用了spring 事务,,该事务里面执行大量的读操作,,,读太多   直接把内存用完了,,







参考

关于 Shallow Size 跟 Retained Size

http://kenwublog.com/understand-shallow-and-retained-size-in-hprofling

http://blog.csdn.net/xch_w/article/details/7857047

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值