Я отправляю Callable
объектов в ThreadPoolExecutor
, и они, кажется, торчат в памяти.Как обеспечить сбор мусора в FutureTask, который отправлен в ThreadPoolExecutor и затем отменен?
Глядя дампа кучи с помощью инструмента MAT Затмения увидеть, что Callable
объекты которые ссылаются на отзывной переменной FutureTask$Sync
«s. То, что FutureTask$Sync
ссылается на переменную FutureTask
с переменной частотой. Это FutureTask
ссылается на FutureTask$Sync
этой переменной $ 0.
Я прочитал вокруг этого (here, here, и на SO), и кажется, что FutureTask
что вызываемый заворачивают в на ThreadPoolExecutor
«s представить() содержит ссылку на Вызываемый навсегда.
В чем я смущен, так это то, как обеспечить, чтобы FutureTask
собирал мусор, чтобы он не продолжал удерживать вызываемый в памяти и удерживать в памяти все, что вызываемый может содержать в памяти?
Чтобы подробно рассказать о моей конкретной ситуации, я пытаюсь реализовать ThreadPoolExecutor
таким образом, чтобы все предоставленные задачи можно было отменить при необходимости. Я пробовал несколько разных методов, которые я нашел в SO и в других местах, например, полностью отключив исполнителя (с shutdown()
, shutdownNow()
и т. Д.), А также сохраняя список возвратов фьючерсов на submit()
и вызывая отмену для всех них, а затем очищая список фьючерсы. В идеале я бы хотел не закрывать его, а просто cancel()
и убирать при необходимости.
Все эти методы, похоже, не имеют значения. Если я отправлю вызываемый в пул, есть хороший шанс, что он в конце концов будет торчать.
Что я делаю неправильно?
Спасибо.
Edit:
В соответствии с просьбой, вот конструктор для 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)
или
getQueue.clear()
или Перебор сохраненных ссылок на фьючерсы и вызов:
getQueue.remove(task)
Любой из этих случаев приводит к тому, FutureTask придерживаться вокруг, как описано выше.
Таким образом, реальный вопрос во всем этом - как правильно отменить или удалить элементы из ThreadPoolExecutor, чтобы FutureTask собирал мусор и не просачивался навсегда?
Отправляйте свой код с жесткого пути удаления: 'ThreadPoolExecutor.getQueue(). Remove (future)' будет делать трюк – bestsss
Существует некоторое обсуждение вопроса о том, следует ли использовать метод getQueue(). Есть ли недостаток в этом? – cottonBallPaws
@bestsss Я надеялся, что меня не спросят, что;) В коде много чего происходит, и я не уверен, какие части имеют отношение к этой проблеме. Я надеялся получить общее представление о том, что может вызвать утечку в отношении FutureTask. Есть ли какая-то конкретная деталь, которую вы хотите увидеть? – cottonBallPaws