春天容器的垃圾收集

时间:2012-05-07 11:22:22

标签: java spring garbage-collection singleton out-of-memory

我在我的应用程序中使用Spring框架(版本3.0.3)。最近,我遇到了这个令人讨厌的java.lang.OutOfMemoryError: Java heap space错误。执行后几小时的应用程序运行后,错误并未立即发生。在那之前,应用程序将运行完全正常,然后突然jvm将崩溃,从而导致内存不足错误 经过广泛调查,我认为这个问题与Spring有关。我注意到所有类,只要需要注入bean,就会创建一个新的XMLBeanFactory实例。也就是说,他们在开始时都有这个代码:

XmlBeanFactory beanfactory = new XmlBeanFactory(new ClassPathResource("SpringConfig.xml"));
Bean myBean = beanfactory.getBean("MyBean");

我知道不建议这样做。您只需要一个Spring容器实例,并为所有Bean创建请求引用该实例。所以我通过单例实现了SpringFactory,从而始终创建XMLBeanFactory的单个实例 进行上述更改似乎已解决了内存泄漏问题! 我现在还不能下定决心:

  1. 即使我使用弹簧容器的多个实例来获取bean,当容器超出范围时,它应该释放所有bean引用,使所有bean可用于垃圾收集。是什么导致内存泄漏问题呢?正如我所提到的,只使用单例容器导致内存泄漏消失。如果需要,我可以提供进一步的细节。
  2. 我们之前使用多个容器的原因是因为豆子不是无状态的。为了解决这个问题,在我的单例弹簧容器中,我将所有bean范围都设为 prototype 。这种做法是否正确?
  3. 更新
    在我将所有代码添加到我的所有Spring bean之后,我想出了有趣的发现:

    protected void finalize()
    {
    System.out.println(this +" object is garbage collected");
    }
    

    我通过让每个类实例化一个新的Spring容器然后获取bean来运行代码。几乎所有创建的bean都打印了上面的注释。这意味着所有的Spring bean都会被清理干净。然而,用完的内存随着时间的推移而不断增加。
    当我通过让所有类使用相同的Spring容器来做同样的事情时,使用的内存保持或多或少稳定。这让我觉得Spring容器有记忆 所以问题是,什么时候是Spring容器(如上面的代码所示)垃圾收集?我认为一旦它超出范围就有资格进行垃圾收集!!
    似乎Hibernate Session Object正在缓存资源并阻止内存。我不确定这一点,但堆转储分析显示Hibernate'字符串'是主要的内存持有者,例如。一些字符串有sql查询和hibernate创建的别名。但我想知道如何以及为什么Hibernate缓存(我不使用二级缓存)只会在我使用多个Spring容器时引起问题!
    更新
    最后,我能够确定是什么阻碍了记忆。它是Hibernate生成的主缓存。我们getHibernateTemplate().clear()已清除对象。但是,每个会话都会缓存sql查询和hibernate属性,并且每个spring容器都会创建一个新会话。由于缓存应在会话关闭时自动清除,因此内存增长意味着会话未关闭。当我在DAO课程结束时明确地getHibernateTemplate().getSessionFactory().close()时,我没有记忆问题,这进一步得到了验证 所以,关注的是,即使容器本身超出范围,为什么spring hibernate模板不会关闭会话?我没有在代码中的任何地方显式处理会话,即使我有一个运行的线程,问题仍然存在。让我觉得框架实现本身出了问题!

2 个答案:

答案 0 :(得分:4)

你得到的OutOfMemoryError究竟是什么?我估计它是java.lang.OutOfMemoryError: PermGen space

如果是这样,这里有解释:

每个spring容器使用不同的类加载器(但它们都具有相同的父类加载器)。加载类时,它被放入永久生成内存而不是堆中,默认情况下它们永远不会被JVM垃圾收集。加载了不同类加载器的同一个类被认为是不同的,因此,当您创建更多新的Spring IoC并且最终耗尽java.lang.OutOfMemoryError: PermGen space的空间时,永久代将被填满。

要解决此问题,应为您的JVM启用类卸载选项:

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

对于其他类型的内存不足错误,我目前看不到任何解释。除非使用线程,否则在Java中创建内存泄漏非常困难。

答案 1 :(得分:1)

  1. 您的容器是否真的超出范围,或者是否已在内部注册?

  2. Spring让你的类无状态的另一点是你拥有尽可能少的实例,并在启动时根据需要加载它们。所以你的范围应尽可能是单身,如果不是,你应该问自己为什么它不是单身,我可以这样做。

相关问题