Я отправляю Callable
объекты в ThreadPoolExecutor
, и кажется, что они застряли в памяти.
Посмотрев дамп кучи с помощью инструмента MAT для Eclipse, вы увидите, что на объекты Callable
ссылается вызываемая переменная FutureTask$Sync
. На этот FutureTask$Sync
ссылается переменная sync FutureTask
. На этот FutureTask
ссылается переменная this $ 0 FutureTask$Sync
.
Я читал об этом (здесь, здесь и на SO) и похоже FutureTask
, в который вызываемый объект заключен в ThreadPoolExecutor
submit (), навсегда хранит ссылку на вызываемый объект.
Что меня смущает, так это как гарантировать, что FutureTask
получит сборщик мусора, чтобы он не продолжал удерживать вызываемый объект в памяти и удерживать все, что вызываемый объект может удерживать в памяти?
Чтобы предоставить более подробную информацию о моей конкретной ситуации, я пытаюсь реализовать ThreadPoolExecutor
таким образом, чтобы при необходимости можно было отменить все отправленные задачи. Я пробовал несколько разных методов, которые нашел на SO и в других местах, например, полностью выключил исполнителя (с shutdown()
, shutdownNow()
и т. Д.), А также сохранил список фьючерсов, возвращаемых submit()
, и вызвал отмену для всех, а затем очистил список фьючерсы. В идеале я бы хотел не выключать его, а просто cancel()
и убирать его, когда это необходимо.
Кажется, что все эти методы не имеют значения. Если я отправлю вызываемый объект в пул, велика вероятность, что он останется.
Что я делаю неправильно?
Спасибо.
Изменить:
По запросу вот конструктор ThreadPoolExecutor.
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
После дальнейшего тестирования я вижу, что если я позволю задачам, которые были отправлены в ThreadPoolExecutor, завершиться, то утечки не будет. Если я попытаюсь отменить их каким-либо образом, например:
shutdownNow()
Или сохраните ссылку на будущее и вызовите отмену для нее позже:
Future referenceToCancelLater = submit(task);
...
referenceToCancelLater.cancel(false);
Или удалив их из очереди такими методами, как:
getQueue.drainTo(someList)
or
getQueue.clear()
или Цикл по сохраненным ссылкам на фьючерсы и вызов:
getQueue.remove(task)
Любой из этих случаев приводит к тому, что FutureTask остается, как описано выше.
Итак, реальный вопрос во всем этом заключается в том, как правильно отменить или удалить элементы из ThreadPoolExecutor, чтобы FutureTask собирал мусор и не просачивался навсегда?
ThreadPoolExecutor.getQueue().remove(future)
сделает свое дело - person bestsss   schedule 07.02.2011ThreadPoolExecutor
API, использовать ее по своему усмотрению (опасность).ThreadPoolExecutor
использует такую очередь, например, в shutdownNow (). Опять же, ваша проблема не в очереди. Вы сливаете что-л. Где-то еще - person bestsss   schedule 07.02.2011ThreadPoolExecutor
, как вы создаете, какую очередь вы используете и отдыхаете, есть ли у вас ЛЮБОЙ поток для обработки отмененных фьючерсов, они должны быть удалены из очереди, когда придет их время, что для запланированная очередь исполнителя может быть далеко по времени. - person bestsss   schedule 07.02.2011PauseCancelThreadPoolExecutor
, что это? Вы не используетеThreadPoolExecutor
. Покажите реализацию класса. Поскольку Queue.clear () не удаляет ссылки, они хранятся где-то в этом загадочном классе - PauseCancelThreadPoolExecutor. - person bestsss   schedule 07.02.2011ThreadPoolExecutor
), поэтому последний вопрос: где вы хранитеreferenceToCancelLater
, вы также должны удалить его из этой структуры. - person bestsss   schedule 07.02.2011