我在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返回的实时结果:
我的问题:
Options
但这不会阻止内存泄漏?如果需要什么,请告诉我们将提供什么。
更新
经过更多的测试后,我更担心问题在于MyBatis持有对检索结果的引用,因此它们不会随着时间的推移而被垃圾收集。在完成20次查询调用之后,等待我即使在30分钟后也没有观察到垃圾回收。我所做的只是调用方法:List<AisDynamic> adList = mapper.getRecords(from, to, sys);
答案 0 :(得分:3)
我在周末进行了测试,看来我解决了这个问题。 感谢@partlov的建议,虽然它不是解决方案让我再次测试问题,但我发现了真正的问题。
问题是我负责处理来自用户的查询请求的客户端堆积了线程(正在执行查询)。由于当我对客户端进行压力测试时请求非常频繁,因此当前一个查询未完成时,即使我通过设置和检查查询的run()
方法中的标志来取消它们,下一个查询也会启动。这出现在查询的会话仍在与数据库交谈的情况下,例如当一个选择有30k +结果。因此,尽管取消标志已被引发,但由于查询正在从数据库中检索结果,因此尚未检查。这足以让下一个查询启动,所以如果它也有很多结果,那么客户端堆积的线程实际上会消耗越来越多的内存。
由于似乎没有办法(我知道)取消与数据库通信的会话(例如选择查询)(在MyBatis
中),我必须自己实施一个保护它的机制。我在我的客户端实现的机制确保下一个查询在上一个查询(为同一个用户执行)完成之前不会启动。因此,现在查询会在客户端退出其run()
方法时通知客户端,然后才能启动同一用户的下一个查询。
更新我从经验中了解到,通过调用{{1}的close()
方法来中止/取消长检索事务的唯一和有点脏的方式(根据我的口味)事务使用的实例。这将导致异常(下面的示例),必须按预期捕获和处理。
SqlSession