【问题标题】:High GC load using Hibernate使用 Hibernate 的高 GC 负载
【发布时间】:2014-01-29 15:18:45
【问题描述】:

我已经使用 Spring MVC + Hibernate 开发了一个 Web 应用程序,并且在运行负载测试时,它似乎过于频繁地调用垃圾收集器。恐怕这可能与我管理 Hibernates 会话的方式有关。

我有一个 AbstractDao,我的所有 DAO 对象都扩展了它:

public class AbstractDaoHibernateImpl {

    protected GenericDataBaseExceptionHandler exceptionHandler;
    private SessionFactory sessionFactory;  

    public AbstractDaoHibernateImpl() {
    }

    public void setExceptionHandler(GenericDataBaseExceptionHandler exceptionHandler) {
        this.exceptionHandler = exceptionHandler;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    protected Session getSession() {
        return sessionFactory.getCurrentSession();
    }

}

在 spring 实体 bean 配置中,我这样定义每个 DAO:

   <bean name="userDao" class="com.kelmer.dao.UserDaoImpl">
        <property name="sessionFactory" ref="SessionFactory" />
        <property name="exceptionHandler" ref="defaultSpringExceptionHandler" />
    </bean>

然后这是来自我的一个 DAO 的示例方法:

    @Override
    public EstacionVO findById(Long id) throws InstanceNotFoundException {
        User e = (User ) getSession().createQuery(SELECT_USER_BY_ID).setParameter("userId", id).uniqueResult();
        if (e == null) {
            throw new InstanceNotFoundException ("No user with provided Id", User.class);
        }
        return e;
    }

老实说,我可以看到任何可能导致内存泄漏的东西,但我又不是真正的专家。我在做会话管理吗?我知道我从一些遗留代码中获取了来自 AbstractDao 的代码,我担心这可能是内存问题所在,因为没有明确的会话关闭或终结。

附言。对于事务管理,我在 Spring 上下文中使用 &lt;tx:annotation-driven /&gt;,并使用 @Transactional 注释每个方法。

【问题讨论】:

  • 我会使用 Session.load(class, PrimaryKey) 通过其主键加载对象,而不是使用查询。
  • 这只是一个示例查询,并非真实案例场景
  • 也许你应该在提问时发布真实的代码。
  • 也许我只是想说明我执行查询的方式,而不是查询本身。问题存在于整个应用程序中,所以我的猜测是它与任何特定查询无关。
  • 如果您使用的是 Spring 并且您有适当的 tx 管理设置,则应在事务完成后关闭会话。如果您没有正确的 tx 或 spring 的错误 tx 集成,您可能会泄漏会话。但是,如果没有您的实际 tx 配置和/或 spring 设置,这很难确定。

标签: java spring hibernate spring-mvc garbage-collection


【解决方案1】:

乍一看,您的代码中似乎没有任何异常。

运行性能监视器以查看创建了哪些对象。

除非问题是微不足道的,否则仅通过查看代码很难看出性能损失在哪里,而且在 90% 的情况下,任何“一定是这样”的说法都被证明是错误的。

【讨论】:

  • 你能推荐一个好的性能监视器吗?我想运行对我的应用施加压力的测试
【解决方案2】:

您的休眠会话创建策略是什么。您的代码是否一次又一次地使用相同的会话? 而不是:

protected Session getSession() {
    return sessionFactory.getCurrentSession();
}

尝试为每个请求打开一个新会话:

protected Session getSession() {
    return sessionFactory.openSession();
}

每个会话都有一个会话缓存,所有检索或持久的对象都添加到该缓存中。如果您继续使用同一会话来查询多对多实体,则“可能”会导致这种情况。

尝试更改,如果有帮助请告诉我们。

正确的方式

使用其中一种性能监控工具来查看问题的真正原因:
http://java.dzone.com/articles/java-performance-troubleshooti-0

【讨论】:

  • 在 Spring 世界中,您永远不应该使用 openSession,因为这会导致 Spring 无法管理的休眠会话,这会导致您遇到各种问题。
猜你喜欢
  • 2012-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-26
  • 2016-03-19
  • 2017-07-11
相关资源
最近更新 更多