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 FutureTask
sync variable. Que FutureTask
se hace referencia en el FutureTask$Sync
esta 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?
publique su código, como de manera difícil eliminar: 'ThreadPoolExecutor.getQueue(). Remove (future)' hará el truco – bestsss
Hay alguna discusión sobre si getQueue() debería utilizarse de esa manera. ¿Hay realmente un inconveniente para hacerlo de esa manera? – cottonBallPaws
@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