2012-10-08 23 views
5

我在NetBeans中探查发现,存活生成的增加不断后,我执行查询:查询中的MyBatis内存泄漏,其结果是平均值列表。 30K行

@Select("SELECT * FROM ais_dynamic WHERE rep_time >= #{from} AND rep_time <= #{to} AND ais_system = #{sys}")  
@Options(useCache=false,fetchSize=8192) 
List<AisDynamic> getRecords(
     @Param("from") Timestamp from, 
     @Param("to") Timestamp to, 
     @Param("sys") int sys); 

这是因为如果是在列表中的对象永远不会释放,虽然他们并没有受到其他任何地方使用并且应该与后台线程一起运行查询并处理其结果。

以下是通过NetBeans配置返回的实时结果: Live results from NetBeans Profiler

我的问题:

  1. 如何防止内存泄漏?
  2. 我该如何优化这个查询,因为我可以看到我开始玩Options,虽然这并没有防止内存泄漏?

如果有什么需要请告诉我和我会提供什么。

UPDATE:

更多的测试后,我更关心的是,问题的MyBatis持有的检索结果的参考规定因此它们不会随时间收集垃圾。在完成20个查询调用之后,等待30分钟后,我观察不到垃圾回收。我所做的只是调用方法:List<AisDynamic> adList = mapper.getRecords(from, to, sys);

+0

我也有MyBatis的内存泄漏。你有没有找到解决你的问题的方法? – Marc

+0

@Marc我观察到它只发生在我检索大量大于10k的行的情况下。为我工作的解决方案是全部使用JDBC和代码全部一起,问题就没有了。甚至测试50k行。虽然它解决了我的问题,但我确实希望一直坚持使用MyBatis,因为它可以节省大量编码,但在这种情况下,这是不可能的。虽然我正在等待更好的解决方案,但谁知道可能需要修复API? – Boro

+0

您可以将此配置添加到您的MyBatis配置文件中,看看是否有任何区别:'' – partlov

回答

3

我在周末测试了它,看起来我解决了这个问题。 感谢@partlov的建议,但它不是解决方案,它让我再次测试问题,并且发现了真正的问题。

问题是我负责处理来自用户的查询请求的客户端堆积了正在执行查询的线程。由于这些请求在我强调测试客户端时非常频繁地发生,因此当前一个查询未完成时,即使通过设置并检查查询的run()方法中的标志来取消它们,下一个查询也开始了。这出现在查询的会话仍然与数据库交谈的情况下,例如当一个选择有30k +的结果。因此,尽管取消标志被提出,但它还没有被检查,因为查询正在从数据库中检索结果。这是足够的时间来开始下一个查询,所以如果它也有很多结果,客户端堆积的线程实际上会消耗越来越多的内存。因为它似乎是没有办法(我知道)取消与数据库交谈的会话(例如选择查询)(在MyBatis),我不得不实现一种机制来保护它自己。我在客户端实现的机制确保下一个查询不会启动,直到前一个查询(针对同一用户执行)完成。因此,现在查询会在客户端退出其run()方法时通知客户端,并且只有这样才会启动针对同一用户的下一个查询。


更新过去的经验,唯一的,有点脏的方式(每我的口味)中止/取消长检索交易学到的是通过调用close()方法SqlSession实例的事务使用。这将导致一个异常(下面的例子),必须按预期捕获和处理。

org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database. Cause: java.lang.NullPointerException 
### The error may exist in YourMapper.java (best guess) 
### The error may involve methodOfTheHandlerInvolved 
### The error occurred while handling results 
### SQL: sqlOfYourQuery 
### Cause: java.lang.NullPointerException 
... (and a trace follows) ...