Как копаться в этой утечке памяти с помощью Eclipse MAT
У меня есть проблема, когда ScheduledThreadPoolExecutor заканчивается 3 миллионами будущих задач. Я пытаюсь определить, к какому типу задач можно обратиться, где запланировано это задание, но я не уверен, как получить какую-либо информацию с этого экрана (я пытался щелкнуть правой кнопкой мыши эти будущие задачи и выбрать различные варианты в меню)., Похоже, что в графическом интерфейсе чего-то не хватает, например, ссылки на реальные runnables или что-то в этом роде
какие-либо идеи о том, как углубиться в дальше?
1 ответ
Некоторые общие вещи
Вы должны знать, что если у вас есть переносимый дамп кучи (phd, см. Типы здесь), то он не содержит фактических данных (примитивов), поэтому вы можете сделать свои выводы только на основе карты ссылок (какие типы содержат ссылку на какие другие виды).
Вы можете попробовать OQL. Это язык, похожий на SQL, с помощью которого вы можете запрашивать ваши объекты.
Один пример:
select * from java.lang.String s where s.@retainedHeapSize>10000
Это возвращает все строки, которые больше, чем ~10k. Вы можете сделать также некоторые функции (например, здесь агрегирование).
Вы могли бы попробовать это.
Что касается текущей проблемы
Если вы проверите источник FutureTask (ниже приведен JDK6):
public class FutureTask<V> implements RunnableFuture<V> {
/** Synchronization control for FutureTask */
private final Sync sync;
...
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
sync = new Sync(callable);
}
...
public FutureTask(Runnable runnable, V result) {
sync = new Sync(Executors.callable(runnable, result));
}
Фактический Runnable упоминается объектом Sync:
private final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -7828117401763700385L;
/** State value representing that task is running */
private static final int RUNNING = 1;
/** State value representing that task ran */
private static final int RAN = 2;
/** State value representing that task was cancelled */
private static final int CANCELLED = 4;
/** The underlying callable */
private final Callable<V> callable;
/** The result to return from get() */
private V result;
/** The exception to throw from get() */
private Throwable exception;
/**
* The thread running task. When nulled after set/cancel, this
* indicates that the results are accessible. Must be
* volatile, to ensure visibility upon completion.
*/
private volatile Thread runner;
Sync(Callable<V> callable) {
this.callable = callable;
}
Таким образом, в GUI откройте объект Sync (не открыт на вашей картинке), а затем вы можете проверить Runnables.
Я не знаю, можете ли вы изменить код или нет, но в целом лучше всегда ограничивать размер очереди, используемой исполнителем, поскольку таким образом вы можете избежать утечек. Или вы можете использовать некоторую постоянную очередь. Если вы применяете лимит, вы можете определить политику отклонения, например, отклонить, запустить в вызывающей программе и так далее. См. http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ThreadPoolExecutor.html для получения подробной информации.