从数据库 1 加载 150 万条记录
从数据库 2 加载 150 万条记录
List<DannDB> dDb = fromNamedQuery(); //return em.createNamedQuery("").getResultList();
List<LannDB> lDb = fromNamedQuery();
比较其数据。
更新/持久化到数据库(使用 JPA)
节目在两小时后结束。
同样的迭代每三个小时发生一次,很多时候会出现内存不足的情况。
以下语句是否有效,对象是否超出范围?
dDb.clear();
or
dDb = null
或者我还能做什么?
最佳答案
假设您的目标是减少 OOME 的发生,而不是考虑所有其他因素......
分配null
到List
object 将使整个列表符合垃圾回收的条件。然后,您需要创建一个新的(可能是空的)列表来替换它。
调用clear()
将具有与清零和重新创建类似的效果1,但详细信息取决于 List
执行。 (例如,在 clear()
上调用 ArrayList
不会释放后备数组。它只是将数组单元格清空。)
如果你可以回收ArrayList
对于与原始大小大致相同的列表,您可以在增长列表时避免垃圾。 (但我们不知道这是 ArrayList
!)
您的用例中的另一个因素是:
List<DannDB> dDb = fromNamedQuery();
(大概)无论如何都会创建一个新列表。这将呈现 clear()
无意义。 (只需将 null
分配给 dDb
,或者让变量超出范围或重新分配新列表。)
最后一个问题是,可以想象该列表是可以最终确定的。这可能意味着删除列表对象需要更长的时间。
总的来说,我不能说分配 null
中的哪一个并调用clear()
对于内存占用会更好。或者其中任何一个都会产生重大影响。但您没有理由不能尝试两种选择,并观察会发生什么。
我可以建议的唯一其他事情是:
- 增加堆大小(以及 RAM 占用空间)。
- 更改应用程序,以便您无需将整个数据库快照保存在内存中。根据比较的性质,您可以按“ block ”进行比较或通过流式传输记录2。
最后一个是唯一可扩展的解决方案;也就是说,这将适用于越来越多的记录。 (对处理更多记录所需的时间取模。)
重要说明:
- 手动运行
System.gc()
不太有帮助。充其量它只会让你的应用程序变慢。 - 由于真正的问题是出现 OOME,因此任何试图通过将内存返还给操作系统来让 JVM 缩小堆的行为都会适得其反。
1 - 从存储管理的角度来看类似。显然,清除列表和创建新列表之间存在语义差异;例如如果您的应用程序的其他部分引用了原始列表。
2 - 你们中足够大的人会记得使用磁带存储实现工资单系统的经典方法。如果您可以按相同的键顺序从两个数据源中进行选择,您也许可以使用经典方法来比较它们。例如,并行读取两个结果集。
关于Java:clear()大尺寸列表有助于快速垃圾收集吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67901163/