【问题标题】:Possible Memory Leak due to org.hibernate.internal.SessionFactoryImpl由于 org.hibernate.internal.SessionFactoryImpl 可能导致内存泄漏
【发布时间】:2013-07-23 07:32:43
【问题描述】:

我用 Java 制作了 MVC webapp,但是当我运行它时,每天一次,由于内存错误,它再次关闭。

这个错误是这样的: 线程“http-apr-12136-exec-42”中的异常 java.lang.OutOfMemoryError:Java 堆空间

java.sql.SQLException: java.lang.OutOfMemoryError: Java 堆空间

我有崩溃统计信息的 hprof,其中具体是如何使用内存的。如果我使用 Eclipse Memory Analizer 打开 hprof,我会得到以下结果:

在rar中:https://mega.co.nz/#!Ht41xJDJ!MooePBSv5yOYSNN5OuvF7Afn2rcN-KJ2tXGSsgqtsaI

或在文件夹中:https://mega.co.nz/#F!6hJUyKbQ!D_Kb23E3KfAJqcd5EeAt0A

在概览报告中,我有这个图形 (OverviewEMA.JPG): 我不知道这张图在说什么……我不明白。

在第二个选项卡,默认报告,我有这个图形(DefaulReport_EMA.JPG): 它说问题可能是“org.hibernate.internal.SessionFactoryImpl”的一个实例。但我不知道如何解决那个实例。

在下一个标签中。在支配树中,再次出现前一个实例,它使用大约 42MB 内存(与显示第一张图相同)。图片是DominatorTree_EMA.JPG

如果我扩展第一个类(给出问题的类),我有这个图形(DominatorTreeExpanded_EMA.JPG):

在下一个选项卡中,在直方图中,图形是这样的 (Histogram_EMA.JPG):

而在Unreachable objects中,结果是这样的(UnreachableObjects_EMA.JPG):

最后这两张图我不太明白

最后,我还有Java VisualVM的报告,我有这个结果(Heapdump_JVM.JPG):

根据该图,除了 Integer 和 String 对象之外,HashMap 对象是问题所在。我认为的 Hashmap 对象是类发送到 jsp 文件的模型对象,它从 JPA 对象(Hibernate 的对象)开始,所以问题可能是这样,但我不知道如何解决它...

有人可以帮我吗?有人知道我该如何解决吗?您需要更多信息吗?

谢谢!

【问题讨论】:

    标签: java hibernate memory-leaks out-of-memory


    【解决方案1】:

    好的。谢谢。

    我应该如何声明EntityManager??

    我正在阅读 Springsource 中 Hibernate 的链接,但我的代码中没有发现任何多余的东西。我不知道该怎么办...

    我的 applicationContext.xml 是这样的:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:p="http://www.springframework.org/schema/p"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    
    
        <!-- holding properties for database connectivity /-->
        <context:property-placeholder location="classpath:jdbc.properties"/>
    
        <!-- enabling annotation driven configuration /-->
        <context:annotation-config/>
    
        <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
          <property name="driverClassName" value="${jdbc.driverClassName}"/>
          <property name="url" value="${jdbc.url}"/>
          <property name="username"  value="${jdbc.username}"/>
          <property name="password" value="${jdbc.password}"/>
        </bean>
    
        <bean id="entityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
                p:dataSource-ref="dataSource"
                p:jpaVendorAdapter-ref="jpaAdapter">
                <property name="loadTimeWeaver">
                  <bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver"/>
                </property>                             
                <property name="persistenceUnitName" value="springappPU"></property>
        </bean>
    
        <bean id="jpaAdapter"
                class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
                p:database="${jpa.database}"
                p:showSql="${jpa.showSql}"/>
    
        <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
                p:entityManagerFactory-ref="entityManagerFactory"/>
    
        <tx:annotation-driven transaction-manager="transactionManager"/>
    
    
        <!-- Scans the classpath of this application for @Components to deploy as beans -->
        <context:component-scan base-package="com.companyname.springapp.repository" />
        <context:component-scan base-package="com.companyname.springapp.service" />
    
    </beans>
    

    我必须如何制作 applicationContext.xml?以及我应该如何在类中声明 EntityManager?

    或者你认为我应该使用 SessionFactory 吗??

    很抱歉给您带来不便。

    【讨论】:

      【解决方案2】:

      对不起,我不能用空格写,所以我写一个新的答案。

      问题可能是我之前在您的答案评论中输入的文字?我这样声明类控制器。

      @Controller
      public class HelloController {
      
          @RequestMapping(value="/hello.htm")
          public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      

      我多次创建的对象是HttpServletRequest和Response?或者是另一个?

      我不知道我在哪里创建 SessionFactory。

      另一个可能的地方,可能是在 Dao 中,我在所有 Dao 中声明一个这样的实体管理器。

      @Repository(value = "contratoDao")
      public class JPAContratoDao implements ContratoDao {
      
          private EntityManager em = null;
      
          /*
           * Sets the entity manager.
           */
          @PersistenceContext
          public void setEntityManager(EntityManager em) {
              this.em = em;
          }
      

      其中一些可能是问题所在?

      再次感谢!

      【讨论】:

      • 我不喜欢在 DAO 中将 EntityManager 声明为实例变量。如果这是 DAO 服务/外观/管理器,而不是数据实体,那就错了。 EntityManagers (hibernate Sessions) 是针对每个 Web 请求的,并且对于单独的线程是不同的,而不是在应用程序的生命周期内保持和增长/累积数据。
      • 共享 HB Session (JPA EntityManager) 对于多用户/并发使用也是完全不正确的。
      • 好的。我又在仔细阅读 Spring 教程。你说我不应该分享HB Session。是事实?如果你这么说,我该怎么办?我必须使用 SessionFactory 而不是 EntityManager 吗?或者我应该更改我的 applicationContext 或我的 JPADao 的声明?
      • 使用 SessionFactoryUtils.getSession() 获取当前会话,并使用 OpenSessionInView 过滤器在请求处理和视图 (JSP) 呈现期间将 Hibernate Session 绑定到当前线程。 Hibernate Sessions 应该是按请求进行的,而不是长期存在的并在全球范围内共享,因为这是您永久增长和 OOM 问题的原因,并且从线程和多用户的角度来看是完全不正确的。
      • 您还可以使用 SessionFactory 或 EntityManagerFactory(JPA 等效项),并为每个方法调用创建一个 Session/EntityManager。但是以这种方式返回的对象,在 Session 关闭后不能延迟加载。由于我已帮助您并正确回答了问题,您现在可以接受我的上述答案。谢谢。
      【解决方案3】:

      在查看 DominatorTree_Expanded 时,您似乎在重复创建 SessionFactory(内存中有 144 个)。这应该只在启动时创建一次,然后用于创建任意数量的会话。

      关于如何正确使用 Hibernate Session,另请参阅下面的我的 cmets。


      您的 Hibernate 会话应该是请求的本地——并在请求结束时关闭。您可以在控制器处理和视图 (JSP) 渲染期间使用“OpenSessionInView”模式将会话绑定到线程。

      我怀疑,由于您要使用 OutOfMemory,因此您将 Hibernate Session 保留为 Controller 的“实例变量”——或者作为某个地方的静态变量。永远不要这样做。

      由于 Web 请求可能是并发的,因此控制器不应将请求处理状态(例如 Hibernate 会话或可变变量)共享为实例变量。这会导致单独的请求和线程之间发生不必要的交互。

      【讨论】:

      • 谢谢。我正在尝试这样做,但我不知道如何使用 OpenSessionInView。您认为错误在控制器中吗?也许这个? @Controller public class HelloController { @RequestMapping(value="/hello.htm") public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      • Controller 没问题,您设置 SessionFactory 或 ApplicationContext 的方式可能有些奇怪。无论你在做什么,你都做了很多次,而应该做一次。见:static.springsource.org/spring/docs/3.0.x/reference/…
      猜你喜欢
      • 1970-01-01
      • 2016-02-15
      • 2016-07-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-03
      • 1970-01-01
      相关资源
      最近更新 更多