私有方法调用的垃圾回收

3

我在我的Java应用程序中遇到了内存使用问题,但是我无论如何也无法理解为什么垃圾回收器没有解决它。代码如下:

public void foo() {
    for(int i=0; i<50000; i++) {
        bar(i);
    }
}

private void bar(int i) {
    LargeObject o = new LargeObject();
    ...
    dao.save(o);
}

我的问题是LargeObject实例没有被垃圾回收-为了识别这个问题,我用jprofiler进行了分析并查看了堆。LargeObject实例从未被类变量引用,事实上,在bar()之外它们没有被任何地方引用。我感觉像是在抓瞎,但这可能与事务的开始/结束有关吗?我尝试将bar()更改为公共,并且使用Propogation.REQUIRES_NEW进行注释,还将foo()的注释更改为Propogation.NEVER,但都没有成功。
dao中的代码如下:
public void save(LargeObject o) {
    hibernateTemplate.getSessionFactory().getCurrentSession().saveOrUpdate(o);
}

垃圾回收器肯定在运行,因为我在jprofiler中看到了它的活动。foo()花费约30分钟,bar()花费36毫秒,垃圾回收大约每60秒激增一次。
至于为什么我确定它们没有被垃圾回收 - 系统中没有任何引用LargeObject,但是当foo()执行时,堆上的实例数量却在增加。

你怎么知道这些实例没有被收集?如果这些是大型/复杂对象,您是否确保它们没有被其他东西引用?另外,垃圾回收器是否已经运行?如果您在一个紧密的循环中运行,GC可能没有机会做任何工作。 - RQDQ
我记得大对象只有在进行完整的垃圾回收时才会被收集。 - cHao
尝试注释掉这一行代码:dao.save(o); - Azodious
2个回答

4

显然,它们被你的JPA提供程序引用(或任何隐藏在 dao.save()后面的东西)。你让这个引用保留在外部,因此你对它的控制就丢失了。无论你是在私有/公共方法中执行还是如何并不重要。

你可能想要分享更多关于这个"DAO"的信息。


谢谢您的建议 - 我没有考虑到 hibernate 可能会保留它。请查看更新后的问题,其中显示了保存方法背后的代码。您以前遇到过这种情况吗? - James

2
我想补充一下@MaDa的回答,循环可能会给唯一缓存所有大对象实例的会话带来负担。如果它们没有关联,您应该考虑以下方法之一:在保存后刷新会话,或使用新的会话,或为每个LargeObject使用清除的会话。
阅读有关批处理的部分可能有助于您理解问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接