处理大量元素时,Hibernate内存不足exception
我正在尝试处理重量级元素(图像)的集合。 收集的大小在8000-50000条目之间变化。 但由于某些原因,在处理1800-1900条目之后,我的程序属于java.lang.OutOfMemoryError:Java堆空间。
在我理解每次调用session.getTransaction()时,commit()程序应该释放堆内存,但看起来它永远不会发生。 我做错了什么? 这是代码:
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 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 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(); }
你把冲洗与清算混淆了:
-
刷新会话会对数据库执行所有挂起的语句(它会将内存中状态与数据库状态同步);
-
清除会话会清除会话(第1级)缓存,从而释放内存。
因此,您需要刷新和清除会话以恢复占用的内存。
除此之外,您必须禁用二级缓存 。 否则,即使在清除会话后,所有(或大多数)对象仍将保持可访问状态。
我不知道为什么你认为提交事务会释放堆内存。 运行垃圾收集就是这样。
如果您的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 } }
批量获取hibernate
- 使用hibernate ScrollableResult
- 使用逐出
顺便说一句,我尝试了无定位解决方案它给了我这个例外我没有怎么解决(可能你可以改进这个答案) exception细节在这里
org.hibernate.SessionException: collections cannot be fetched by a stateless session
所以我调整了睡眠(延迟)作为它的背景过程而且很长时间在服务器上的资源很少我必须冷却CPU; 午夜工作(没有高峰时间)。
- Spring 3 MVC Hibernate 3.5.4 hibernateTemplate没有关闭连接(非事务性)
- 指定是否使用Spring Data延迟加载
- hibernate 4.3.x – 加载所有实体注释类
- junit测试中的spring-data-jpa beanvalidation
- 单表inheritanceWITHOUT Discriminator列
- 需要一个Hibernate中主键@OneToOne映射的示例
- 例外:无法解析配置:hibernate.cfg.xml
- 为什么在Spring 3.1和hibernate 4中找到当前线程exception的No Session
- 使用EAGER @ElementCollection对find()进行Hibernate LazyInitializationException