我的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()
的执行而增加。
答案 0 :(得分:4)
显然,您的JPA提供程序(或隐藏在dao.save()
后面的任何内容)都会引用它们。你确实让引用在外面,因此你对它的控制就会丢失。无论你是采用私人/公共方法进行操作都无关紧要。
您可能想要分享有关此“DAO”的更多信息。
答案 1 :(得分:2)
我要添加@MaDa的答案,循环可能会导致必须缓存所有Large Objects
个实例的唯一会话的负担。您应该考虑:保存后刷新会话,或者为每个LargeObject
使用新会话或清除会话如果它们不相关
阅读Batch Processing部分可能有助于您了解问题