Как я могу удалить корневую ссылку GC «Java Frame» на Runnable, когда я выгружаю кучу в jvisualvm? - PullRequest
3 голосов
/ 27 октября 2011

Я использую jvisualvm для проверки утечек памяти в моем приложении. Когда я делаю дамп кучи, иногда остаются открытыми несколько объектов, которые должны были быть собраны мусором.

Когда я выполняю на них команду «Показать ближайший GC Root», это показывает, что корень - это класс, который я определил и который реализует интерфейс Runnable. Ссылка указана как (java frame), что, как я знаю, связано с многопоточностью. Когда я раскрываю дерево для этого узла, он открывается и показывает <no references>. Так что кажется довольно ясным, что это не ссылка, которую я держу открытой, а нечто внутреннее в Java.

Объект GC Root, указанный в jvisualvm, имеет тип AnalyticNode extends Node, который, в свою очередь, равен Node implements Runnable. Этот корневой объект никоим образом не имеет ничего общего с AWT, Swing или любыми тяжелыми компонентами пользовательского интерфейса, несмотря на используемое слово «рамка». В этом случае слово «рамка» относится к многопоточности.

Так Java хранит ссылку на последний Runnable где-нибудь, который будет держать это открытым? Есть ли какой-нибудь способ, которым я могу сказать Java освободить эту ссылку, чтобы она могла быть должным образом собрана мусором для моего дампа кучи?

Что здесь происходит?

Ответы [ 2 ]

4 голосов
/ 27 октября 2011

В этом контексте «кадр» относится к кадру стека.Похоже, что Runnable вместо того, чтобы (или в дополнение к) быть целью выполняющегося потока, хранится в локальной переменной в кадре в стеке исполняющего потока.Он будет иметь право на сбор, когда метод, связанный с фреймом, вернется.


Исходя из последующих комментариев, я предполагаю, что в вашем пользовательском пуле потоков есть локальная переменная, для которой Runnableназначены.Вероятно, он находится в слишком большой области видимости (вне цикла) и не очищается (присваивается null) после каждой итерации цикла.

Я могу воспроизвести ситуацию, которая соответствует описанному с кодом, подобным этомув рабочем потоке:

Runnable target = null;
while (true) {
  target = queue.take();
  target.run();
}

Очистка объявления target так, чтобы он был внутри цикла, устраняет проблему.

Я бы предложил перейти к реализации Executorиз ядра Java или опубликовать соответствующий код вашего пользовательского пула потоков, если вы хотите это исправить.

1 голос
/ 27 октября 2011

Что вы сделали с созданным вами объектом?Вы создали тему и указали на нее?В этом случае вы должны убедиться, что поток остановлен, позволяя коду в run () завершить работу.

...