Java 在处理大量元素集合时发生休眠内存不足异常
我正在尝试处理重元素(图像)的收集。收集的数量在8000到50000个条目之间变化。但由于某些原因,在处理1800-1900个条目后,我的程序出现了java.lang.OutOfMemoryError:java堆空间 在我的理解中,每次调用session.getTransaction().commit()程序时都应该释放堆内存,但看起来好像从来没有发生过。 我做错了什么?代码如下:Java 在处理大量元素集合时发生休眠内存不足异常,java,performance,hibernate,out-of-memory,data-processing,Java,Performance,Hibernate,Out Of Memory,Data Processing,我正在尝试处理重元素(图像)的收集。收集的数量在8000到50000个条目之间变化。但由于某些原因,在处理1800-1900个条目后,我的程序出现了java.lang.OutOfMemoryError:java堆空间 在我的理解中,每次调用session.getTransaction().commit()程序时都应该释放堆内存,但看起来好像从来没有发生过。 我做错了什么?代码如下: private static void loadImages( LoadStrategy loadStrategy
private static void loadImages( LoadStrategy loadStrategy ) throws IOException {
log.info( "Loading images for: " + loadStrategy.getPageType() );
Session session = sessionFactory.openSession();
session.setFlushMode( FlushMode.COMMIT );
Query query = session.createQuery( "from PageRaw where pageType = :pageType and pageStatus = :pageStatus and sessionId = 1" );
query.setString( "pageStatus", PageStatus.SUCCESS.name() );
query.setString( "pageType", loadStrategy.getPageType().name() );
query.setMaxResults( 50 );
List<PageRaw> pages;
int resultNum = 0;
do {
session.getTransaction().begin();
log.info( "Get pages statring form " + resultNum + " position" );
query.setFirstResult( resultNum );
resultNum += 50;
pages = query.list();
log.info( "Found " + pages.size() + " pages" );
for (PageRaw pr : pages ) {
Set<String> imageUrls = new HashSet<>();
for ( UrlLocator imageUrlLocator : loadStrategy.getImageUrlLocators() ) {
imageUrls.addAll(
imageUrlLocator.locateUrls( StringConvector.toString( pr.getSourceHtml() ) )
);
}
removeDeletedImageRaws( pr.getImages(), imageUrls );
loadNewImageRaws( pr.getImages(), imageUrls );
}
session.getTransaction().commit();
} while ( pages.size() > 0 );
session.close();
}
private static void loadImages(LoadStrategy-LoadStrategy)引发IOException{
log.info(“为:+loadStrategy.getPageType()加载图像”);
Session Session=sessionFactory.openSession();
session.setFlushMode(FlushMode.COMMIT);
Query Query=session.createQuery(“来自PageRaw,其中pageType=:pageType和pageStatus=:pageStatus和sessionId=1”);
query.setString(“pageStatus”,pageStatus.SUCCESS.name());
query.setString(“pageType”,loadStrategy.getPageType().name());
query.setMaxResults(50);
列表页;
int resultNum=0;
做{
session.getTransaction().begin();
log.info(“获取页面列表”+resultNum+“位置”);
query.setFirstResult(resultNum);
结果num+=50;
pages=query.list();
log.info(“找到”+页面.size()+页面”);
用于(PageRaw pr:pages){
Set imageUrls=newhashset();
对于(UrlLocator-imageUrlLocator:loadStrategy.getImageUrlLocators()){
imageURL.addAll(
imageUrlLocator.locateUrls(StringConverctor.toString(pr.getSourceHtml()))
);
}
移除删除的ImageRaws(pr.getImages(),imageUrls);
loadNewImageRaws(pr.getImages(),imageUrls);
}
session.getTransaction().commit();
}while(pages.size()>0);
session.close();
}
我不知道为什么您认为提交事务可以释放堆内存。运行垃圾收集可以做到这一点
如果perm gen用完,可能会发生OOM错误
简单的答案是在启动JVM时更改最小和最大堆大小以及perm gen大小,看看它是否消失
我建议使用一个分析器,比如VisualVM,看看运行时消耗内存的是什么。它应该很容易修复
我猜你是想一下子投入太多。将其分成小块,看看是否有帮助。尝试使用session.clear()命令
“完全清除会话。退出所有加载的实例并取消所有挂起的保存、更新和删除。不要关闭打开的迭代器或ScrollableResults实例”您将刷新与清除混淆了:
- 刷新会话将针对数据库执行所有挂起的语句(它将内存状态与数据库状态同步)
- 清除会话将清除会话(第一级)缓存,从而释放内存
除此之外,还必须禁用二级缓存。否则,即使在清除会话之后,所有(或大部分)对象仍然可以访问。本文解决了我的问题
Session session = sessionFactory.getCurrentSession();
ScrollableResults scrollableResults = session.createQuery("from DemoEntity").scroll(ScrollMode.FORWARD_ONLY);
int count = 0;
while (scrollableResults.next()) {
if (++count > 0 && count % 100 == 0) {
System.out.println("Fetched " + count + " entities");
}
DemoEntity demoEntity = (DemoEntity) scrollableResults.get()[0];
//Process and write result
session.evict(demoEntity);//important to add this
}
}
所以我调整了睡眠(延迟)作为后台进程,在服务器资源很低的情况下,我需要很长时间来冷却cpu;午夜工作(没有高峰时间)。我怀疑是因为上课。所以我添加了这一行session.setFlushMode(FlushMode.COMMIT)。但看起来我错了。我以前从未使用过探查器,我想是时候开始了。)对于记录,有效地释放内存的不是垃圾收集,而是对象变得不可访问。这是OP假设在事务提交(隐式刷新)时会发生的情况。如何禁用二级缓存?
session.execute()
会有帮助吗?
org.hibernate.SessionException: collections cannot be fetched by a stateless session