2011-02-06 17 views
9

Estoy enviando Callable objetos a un ThreadPoolExecutor y parece que se quedan en la memoria.¿Cómo asegurar la recogida de basura de una FutureTask que se envía a ThreadPoolExecutor y luego se cancela?

Mirando el volcado del montón con la herramienta para Eclipse MAT ver que los Callable objetos están siendo referenciados por un exigible variables FutureTask$Sync 's. Que FutureTask$Sync se hace referencia en FutureTasksync variable. Que FutureTask se hace referencia en el FutureTask$Syncesta variable $ 0.

He leído todo acerca de esto (here, here, y el SO) y parece que la FutureTask que el exigible se envuelve en al ThreadPoolExecutor 's submit() contiene una referencia a la exigible para siempre.

Lo que me produce confusión es cómo asegurar que FutureTask obtenga la basura recogida para que no continúe reteniendo el llamable en la memoria, y mantenga todo lo que el llamable pueda tener en la memoria?

Solo para dar más detalles sobre mi situación particular, estoy tratando de implementar el ThreadPoolExecutor de una manera que permita que todas las tareas enviadas se cancelen si es necesario. He intentado varios métodos diferentes que encontré en SO y en otros lugares, como cerrar por completo el ejecutor (con shutdown(), shutdownNow(), etc.) y también mantener una lista de los futuros devueltos por submit() y cancelar la llamada en todos ellos y luego borrar la lista de futuros. Idealmente, me gustaría no tener que cerrarlo, y solo cancel() y despejar cuando sea necesario.

Todos estos métodos no parecen marcar la diferencia. Si presento un llamamiento al grupo, es muy probable que termine por quedarse.

¿Qué estoy haciendo mal?

Gracias.

Editar:

Conforme a lo solicitado, aquí es el constructor de la ThreadPoolExecutor.

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { 
    super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); 
} 

Después de más pruebas, puedo ver que si dejo que las tareas que se han presentado hasta la meta ThreadPoolExecutor, entonces no hay ninguna fuga.Si trato de cancelarlos en cualquier caso, tales como:

shutdownNow() 

o guardar una referencia al futuro y llamar a cancelar en él más tarde:

Future referenceToCancelLater = submit(task); 
... 
referenceToCancelLater.cancel(false); 

O retirándolos de la cola con métodos como:

getQueue.drainTo(someList) 

o

getQueue.clear() 

o bucle a través de referencias guardan en el futuro y llamando:

getQueue.remove(task) 

Cualquiera de estos casos hace que el FutureTask a quedar como se describió anteriormente.

Entonces, ¿la verdadera pregunta de todo esto es cómo cancelar o eliminar correctamente los elementos de un ThreadPoolExecutor para que FutureTask se recoja como basura y no se filtre para siempre?

+1

publique su código, como de manera difícil eliminar: 'ThreadPoolExecutor.getQueue(). Remove (future)' hará el truco – bestsss

+0

Hay alguna discusión sobre si getQueue() debería utilizarse de esa manera. ¿Hay realmente un inconveniente para hacerlo de esa manera? – cottonBallPaws

+0

@bestsss Esperaba que no me lo pidieran;) El código tiene muchas cosas en juego y no estoy seguro de qué partes son relevantes para este tema. Esperaba tener una idea general de lo que podría estar causando una fuga en lo que respecta a FutureTask. ¿Hay alguna parte específica que quieras ver? – cottonBallPaws

Respuesta

1

no pude conseguir nada a trabajar por lo que ocurrió con la siguiente solución. Aquí hay una descripción aproximada: Creé una matriz en el ThreadPoolExecutor que realizaba un seguimiento de los ejecutables que estaban en la cola. Luego, cuando tuve que cancelar la cola, hice un bucle y llamé a un método de cancelación en cada uno de los ejecutables. En mi caso, todos estos ejecutables fueron una clase personalizada que creé y su método de cancelar simplemente estableció una bandera cancelada. Cuando la cola llamaba al siguiente para procesar, en la ejecución del ejecutable vería que se canceló y se saltaría el trabajo real.

De modo que todos los ejecutables se eliminan rápidamente uno por uno, ya que se ve cancelado.

Probablemente no sea la mejor solución, pero funciona para mí y no pierde memoria.

+0

Hola, creo que estoy teniendo el mismo problema que tuviste. ¿Has descubierto cómo resolver el problema de una manera más limpia?) En realidad, deberían existir algunas clases de Java que se ocupen de la eliminación de esos hilos caducados. Cheers – Simone

+0

@Simone, lamentablemente no, no pude encontrar algo más incorporado. Todavía estoy usando el método anterior. Sin embargo, funciona bien, solo me costó un poco prepararme. – cottonBallPaws

+0

Gracias por la respuesta. Entonces, ¿el método de cancelar (clase Ejecutable) libera la memoria asignada por el hilo o lo hizo manualmente? – Simone

1

Como solución podría hacer algo como:

class ClearingCallable<T> implements Callable<T> { 
    Callable<T> delegate; 
    ClearingCallable(Callable<T> delegate) { 
     this.delegate = delegate; 
    } 

    T call() { 
     try { 
      return delegate.call(); 
     } finally { 
      delegate = null; 
     } 
    } 
} 
+0

¿Cuál sería el delegado en este caso? – cottonBallPaws

+1

Su llamante que está en espera dice que quiere que se recoja la basura. – Tom

+0

esto no resuelve nada. El problema no es el 'ThreadPoolExecutor', b/c it, solo, no tiene fugas en las tareas ejecutadas – bestsss

4

De acuerdo con this post, puede llamar al purge en el ejecutor.

+0

dice "Trata de eliminar de la cola de trabajos todas las tareas futuras que se han cancelado. Este método puede ser útil como operación de recuperación de almacenamiento, que no tiene otro impacto en la funcionalidad. Las tareas canceladas nunca se ejecutan, pero pueden acumularse en colas de trabajos hasta que los subprocesos de trabajo puedan eliminarlos activamente. Invocar este método en su lugar intenta eliminarlos ahora. Sin embargo, este método puede no eliminar tareas en presencia de interferencia por otros subprocesos ". ¿Significa que si la tarea ya se está ejecutando pero cae en un punto muerto, no se eliminará? – HoaPhan

Cuestiones relacionadas