2011-04-14 76 views
1

我有一个MySQL表1M行,我是Java持久性API当我执行下面的代码,然后我得到Java堆错误:的Java持久性内存泄漏

int counter = 0; 
while (counter < 1000000) { 
    java.util.Collection<MyEntityClass> data = myQuery.setFirstResult(counter) 
     .setMaxResults(1000).getResultList(); 
    for(MyEntityClass obj : data){ 
     System.out.println(obj); 
    } 
    counter += 1000; 
} 
+8

你有人点击“下一步”2500次? – 2011-04-14 14:38:02

回答

7

我不知道的JTable真的挂到当你点击“下一步”时,所有这些旧的参考文献。我不相信这是一个持久性问题。无论支持JTable的数据结构如何,我都要确保在添加下一批记录之前将其清除。这样,旧值可以被GC'd。

您的JTable不应该有ResultSet。最好有一个持久层来隐藏客户的这些细节。查询一批值(而不是整个数据集的),将其从ResultSet加载到数据结构中,然后在finally块中关闭ResultSet和Statement。您需要在创建它们的方法范围内关闭这些资源,或者您要求麻烦。

+1

我不建议一次检索1M行,出于内存和性能原因。请参阅我的回答,以获得有关您在用户下次点击时检索网页的建议。 – AndyT 2011-04-14 15:28:03

+0

我不建议检索1M行,每次都对子集进行查询,将其加载到数据结构中,然后关闭,我将编辑我的问题以进行说明 – duffymo 2011-04-14 17:23:30

0

看起来你的结果集在他的特殊情况下不适用于GC。检查你的代码,看看这个结果集的链接真的在哪里发生,从而发生内存泄漏。

1
  • 这是一个Java EE或Java SE应用程序?
  • 你是如何处理你的实体经理 ?

实体管理器典型地与上下文相关联。在事务处理期间,您恢复的每个实体都将放入其中,并且它将成为所有实体的缓存,当事务提交时,JPA将在上下文中搜索修改并将更改提交到数据库。

这意味着,如果恢复一个百万行,你会在你的背景百万的实体,直到您关闭实体管理器,他们不会被垃圾收集的。

由于您指的是JTable,我只能假设这是一个JSE应用程序。在这种类型的应用程序中,您完全控制了上下文。在这种类型的应用程序中,上下文和实体管理器之间存在一对一的关系(在Java EE环境中并非总是如此)。

这意味着您可以创建每个请求的实体管理器(即交易或交谈)或实体管理器应用程序的整个生命周期。

如果您使用的是第二种方法,你情境永远不会被垃圾收集,并从更大变得读取数据库中的多个对象,直到你最终可能会达到内存的问题像你描述的那个。

我不是说这是你的问题的原因,但它肯定会是在寻找根本原因带了好头,你不觉得吗?

+0

没有提及我可以看到的JPA。如果他/她使用直接JDBC,因为我怀疑它们是,那么这些都不适用。 – duffymo 2011-04-14 14:54:46

+0

@duffymo它在问题的标记上 – 2011-04-14 14:58:29

+0

nope,我没有直接使用jdbc我有一个实体类,它对应于我的表 – user704006 2011-04-14 15:04:52

2

问题几乎可以肯定的是你的resultSet对象正在缓存整个结果集,这会为这么大的查询消耗大量的内存。

不像现在那样重置结果集上的索引 - 它不清除缓存的结果,我建议你编写一个查询来检索给定页面的相应行,并且每次执行页面更改。每次丢弃旧的结果集,以确保您不会缓存任何内容。

根据您使用的数据库,您可以使用rownum伪列(Oracle),row_number()(DB2,MSSQL)函数或limit x offset y语法(MySql)。

+0

+1巨大的结果集不好。 – 2011-04-14 15:30:34