我正在运行一个实用程序类作为java应用程序。该类读取包含500万条记录的csv文件,并尝试在数据库中保存大约125k条记录。中途通过我有堆空间错误。完整文件大约需要5-6个小时才能运行。添加thread.sleep方法是否有助于清理资源,因为它是作为Java应用程序运行的?我使用spring数据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
答案 0 :(得分:3)
我怀疑最大的问题在于你使用Hibernate将数据插入数据库的方式。
当您调用EntityManager.persist()
或EntityManager.merge()
时,您正在使用的实体将添加到EntityManager
实例的PersistenceContext中(值得了解实体生命周期,如上所述) here。)
您可以将PersistenceContext视为Hibernate使用的一种缓存,以避免为已在当前工作单元中加载的对象不必要地访问数据库。此外,Hibernate使用PersistenceContext执行脏检查,以便它了解在事务提交时需要刷新哪些对象。
对于少量对象,这很好。当您使用大量对象时,问题就出现了,因为Hibernate保留了对PersistenceContext中每个对象的引用,原因如上所述。
因此,重要的是,当您进行大批量插入时,您需要仔细管理PersistenceContext的大小,或者以特定间隔明确刷新和清除它,或者使用无状态EntityManager
批量插入。
Hibernate很好地解释了如何使用&#34;很多&#34;一次性实体here。我怀疑遵循这个建议将解决你的大部分记忆问题。
答案 1 :(得分:2)
我将尝试回答您的具体问题,即Thread.sleep()
对内存问题的影响 - 我相信其他人会告诉您如何控制Hibernate的足迹。
我只知道一种情况,即睡眠你的应用程序线程有助于避免内存不足的情况,那就是你大量使用定义了Object.finalize()
方法的类的实例。这样的实例经历了两轮可达性测试,并且必须执行最终化方法;作为垃圾收集的一部分,所有实例的finalize方法都在一个线程上执行。如果您在多个线程上创建可终结垃圾的速度比单个终结器线程可以处理的速度快,那么即使您有大量可用于收集的垃圾,也会出现OutOfMemoryError。通过休眠减慢应用程序线程,您可以给终结器线程一个赶上的机会。
在这种情况下,这几乎肯定不是你的问题(你还有其他明显的原因导致堆空间不足),睡眠不会让你获益。
答案 2 :(得分:1)
你还必须刷新()EntityManager数据库并定期清除()它。
这很可能是你内存不足的原因。