5

我在 NetBeans Profiler 中观察到,在执行查询后,Surviving Generations 不断增加:

@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 Profiler 返回的实时结果: NetBeans Profiler 的实时结果

我的问题:

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

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

更新:

经过更多测试后,我更担心问题在于 MyBatis 持有对检索结果的引用,因此它们不会随着时间的推移而被垃圾收集。在进行了 20 次查询调用然后等待后,我观察到即使在 30 分钟后也没有垃圾收集。我所做的就是调用该方法:List<AisDynamic> adList = mapper.getRecords(from, to, sys);

4

1 回答 1

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) ...
于 2013-04-25T15:50:33.947 回答