我正在将实用程序类作为 java 应用程序运行。该类(class)读取了包含 500 万条记录的 csv 文件,并尝试在数据库中保存大约 125k 条记录。进行到一半时,我遇到了堆空间错误。完整文件运行大约需要 5-6 小时。考虑到这是作为 java 应用程序运行,添加 thread.sleep 方法是否有助于清理资源?我正在使用 spring data jpa 每 1k 行插入一次。
String strLine;
List<Provider> providers = new ArrayList<Provider>();
int count = 0;
while ((strLine = br.readLine()) != null) {
String[] providerDetails = strLine.split(",(?=([^\"]*\"[^\"]*\")*[^\"]*$)");
if (providerDetails[31].substring(1, (providerDetails[31].length() - 1)).equals("MD")
|| providerDetails[31].substring(1, (providerDetails[31].length() - 1)).equals("DC")) {
count++;
// add provider to repository
providers.add(convertToProvider(providerDetails));
if (count % 1000 == 0) {
providerRepository.save(providers);
providers.clear();
Thread.sleep(2000);
}
}
}
我可以做任何其他优化来解决内存问题吗?我正在使用 eclipse 并给了它足够的内存
-Xms128m
-Xmx1536m
-XX:MaxPermSize=768m
-XX:-UseGCOverheadLimit
最佳答案
我怀疑最大的问题在于您使用 Hibernate 将数据插入数据库的方式。
当您调用 EntityManager.persist()
或 EntityManager.merge()
时,您正在使用的实体将添加到 EntityManager 的 PersistenceContext 中
实例(值得您了解实体生命周期,如here所述。)
您可以将 PersistenceContext 视为一种缓存,Hibernate 使用它来避免对当前工作单元中已加载的对象进行不必要的数据库访问。此外,Hibernate 使用 PersistenceContext 执行脏检查,以便了解事务提交时需要刷新哪些对象。
这对于少量对象来说没问题。当您处理大量对象时,问题就会出现,因为出于上述原因,Hibernate 会保留对 PersistenceContext 中每个对象的引用。
因此,当您进行大批量插入时,请仔细管理 PersistenceContext 的大小,要么以一定的时间间隔显式刷新和清除它,要么使用无状态的 EntityManager ,这一点很重要用于批量插入。
Hibernate 对如何一次性处理“大量”实体有很好的解释 here 。我怀疑遵循该建议将解决您的大部分内存问题。
关于java - Thread.sleep 是否可以减少读取和保存大文件时的内存问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23431535/