Hibernate内存溢出分析一例

 

公司业务系统在进行压力测试时,压测24小时后系统发生内存溢出。经过分析读dump文件,发现org.hibernate.stat.StatisticsImpl类的hashmap类型的变量存储了大量数据(3百多万条),此成员变量消耗了2g的内存。如下图:

    

org.hibernate.stat.StatisticsImpl类是性能统计的功能实现,当hibernate.generate_statistics配置为true时就会启用此功能。因此此功能在生产环境下必须关闭,否则此处消耗的系统资源会影响系统性能并且最终会发生oom。

原理分析及总结

    进一步分析,org.hibernate.stat.StatisticsImpl的成员queryStatistice就是内存的溢出点:

    org.hibernate.stat.StatisticsImpl的源代码:

public class StatisticsImpl implements Statistics, StatisticsImplementor {

 

    /** entity statistics per query string (HQL or SQL) */

    private final Map queryStatistics = new HashMap();

 

//对此变量存储数据的方法:

public synchronized QueryStatistics getQueryStatistics(String queryString) {

        QueryStatistics qs = (QueryStatistics) queryStatistics.get(queryString);

        if (qs==null) {

            qs = new QueryStatistics(queryString);

            queryStatistics.put(queryString, qs);

        }

        return qs;

}

}

    即以查询的sql或hql作为queryStatistics的key,此map的数量量过大说明查询的sql或hql语句的查询条件不是变量绑定或预编译的写法,在进行大量的动态sql、hql查询时就会导致此问题。

 

从此次问题也说明以下两点很重要:

  1. 在编写sql、hql是应采用变量绑定或预编译的写法(如where id=?或where id=:id),避免出现大量不同的sql语句。如未遵循这个规则,在数据库中也会发生比较高的硬简析。
  2. hibernate.generate_statistics的功能在生产环境应禁用。
posted @ 2016-04-11 14:47  bingjava  阅读(3774)  评论(0编辑  收藏  举报