java - spring容器的垃圾收集

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

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

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

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

  1. 即使我使用多个 spring 容器实例来获取 bean,当容器超出范围时,它也应该释放所有 bean 引用,使所有 bean 都可用于垃圾收集。是什么导致了内存泄漏问题呢?正如我所提到的,仅使用单例容器会导致内存泄漏消失。如果需要,我可以提供更多详细信息。
  2. 我们之前使用多个容器的原因是因为 bean 不是无状态的。为了解决这个问题,在我的单例 spring 容器中,我将所有 bean 的作用域设为 prototype。这种做法是否正确?

更新:
在我向所有 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 属性正在为每个 session 缓存,并且每个 spring 容器都会创建一个新 session 。由于缓存应该在 session 关闭时自动清除,内存增长意味着 session 没有关闭。当我在我的 DAO 类结束时显式执行 getHibernateTemplate().getSessionFactory().close() 时没有内存问题,这得到了进一步验证。
所以,问题是,为什么即使容器本身超出范围,spring hibernate 模板也不会关闭 session ?我没有在代码中的任何地方显式处理 session ,即使我有一个线程在运行,问题仍然存在。让我觉得框架实现本身有问题!

最佳答案

您到底得到了哪个 OutOfMemoryError?我估计是 java.lang.OutOfMemoryError: PermGen space

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

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

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

-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

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

关于java - spring容器的垃圾收集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10481195/

相关文章:

java - Tomcat java.lang.OutOfMemoryError : GC overhead limit exceeded 错误

java - neo4j - cypher 与 java api - 插入速度更快

java - 从其他未连接的类接收特定值

java - 使用 JNI 时如何摆脱 LD_PRELOAD

Java Spring有一种方法可以扩展@Scheduled来读取文件

java - spring jpa安装程序无法更新数据库

具有 JSON 内容 + 多个多部分文件的 Spring MVC Rest 服务

java - Tiff 平铺 : how to read a specific tile?

python - PyYAML 内存泄漏

JAVA GC OverheadLimit 错误