2012-10-08 46 views
5

me observaron en NetBeans Profiler que Sobrevivir Generaciones sigue aumentando después de ejecutar la consulta:Pérdida de memoria MyBatis en una consulta cuyo resultado es una lista de prom. 30k filas

@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); 

Es como si los objetos que están en la lista no se liberan a pesar de que no se están utilizando en otro sitio y debe morir con el hilo de fondo ejecutando la consulta y procesando sus resultados.

A continuación se presentan los resultados en directo devueltos por NetBeans Profiler: Live results from NetBeans Profiler

Mis preguntas:

  1. ¿Cómo puedo prevenir la pérdida de memoria?
  2. ¿Cómo puedo optimizar esta consulta, como se puede ver Comencé a jugar con el Options, aunque esto no evitó la pérdida de memoria?

Si se necesita algo, por favor, diga qué y le daré.

ACTUALIZACIÓN:

Después de más pruebas de que estoy más preocupado de que el problema está con MyBatis la celebración de una referencia a los resultados obtenidos por lo tanto no son basura recogida en el tiempo. Después de hacer 20 llamadas de la consulta y esperar, observo que no hay recolección de basura, incluso después de 30 minutos. Todo lo que hago es llamar al método: List<AisDynamic> adList = mapper.getRecords(from, to, sys);

+0

También tengo una pérdida de memoria con MyBatis. ¿Encontró alguna solución para su problema? – Marc

+0

@Marc Observé que ocurre solo en situaciones en las que recupero grandes cantidades de filas de algo más de 10k. La solución que funcionó para mí fue utilizar un código JDBC y todo a mano, todo junto y el problema desapareció. Probado incluso para 50k de filas. A pesar de que resolvió el problema para mí, realmente preferiría mantener MyBatis en todo momento, ya que ahorra mucha codificación, pero en este caso no fue posible. Aunque estoy esperando una solución mejor, ¿quién sabe si se necesita una solución para la API? – Boro

+0

¿Puede agregar esta configuración a su archivo de configuración MyBatis y ver si hay alguna diferencia: '' – partlov

Respuesta

3

Lo probé durante el fin de semana y parece que resolví el problema. Gracias a @partlov por la sugerencia, aunque no es la solución que tengo para probar el problema nuevamente y he descubierto el problema real.

El problema era que mi cliente responsable de manejar las solicitudes de consultas de los usuarios estaba acumulando los hilos (que estaban ejecutando las consultas). Dado que las solicitudes venían con mucha frecuencia cuando puse énfasis en probar al cliente cuando la consulta anterior no se realizó, la siguiente comenzaba a pesar de que las estaba cancelando configurando y verificando un indicador dentro del método run() de una consulta. Esto estaba apareciendo en situaciones cuando la sesión de una consulta todavía estaba hablando con la base de datos, p. cuando un seleccionado tenía 30k + resultados. Por lo tanto, aunque se levantó el indicador de cancelación, aún no se había verificado ya que la consulta estaba en el proceso de recuperar los resultados de la base de datos. Este fue el tiempo suficiente para que comenzara la siguiente consulta, por lo que si también tenía muchos resultados, el cliente estaba acumulando los hilos que consumían más y más memoria.

Dado que parece que no hay forma (que yo sepa) de cancelar una sesión (por ejemplo, una consulta de selección) que se comunica con la base de datos (en MyBatis) tuve que implementar un mecanismo para protegerla. El mecanismo que implementé en mi cliente garantiza que la próxima consulta no se inicie hasta que finalice la anterior (ejecutada para el mismo usuario). Por lo tanto, ahora una consulta informa al cliente cuando sale de su método run() y solo entonces puede iniciarse la siguiente consulta para el mismo usuario.


actualización he aprendido por experiencia que la única manera sucia y un poco (por mi gusto) para cancelar/cancelar una transacción de recuperación a largo es llamando close() método de la SqlSession instancia que utiliza la transacción.Esto dará como resultado una excepción (ejemplo a continuación) que debe capturarse y manejarse según lo previsto.

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) ... 
Cuestiones relacionadas