BufferedImage.getGraphics (), приводящий к утечке памяти, есть ли исправление? - PullRequest
6 голосов
/ 05 июня 2010

У меня проблема с некоторым API-интерфейсом фреймворка, вызывающим метод BufferedImage.getGraphics () и вызывающим утечку памяти. Этот метод делает то, что он всегда вызывает BufferedImage.createGraphics (). На машине с Windows createGraphics () обрабатывается Win32GraphicsEnvironment, которая хранит список listeners внутри своего поля displayChanger . Когда я вызываю getGraphics для моего BufferedImage someChart , someChart SurfaceManager (который сохраняет ссылку на someChart ), добавляется к слушателям карта в Win32GraphicsEnvironment, предотвращающая сбор мусора someChart . После этого ничего не удаляет SurfaceManager someChart из карты listeners .

Обычно суммарный путь, по которому BufferedImage не собирает мусор при вызове getGraphics, выглядит следующим образом:

GC Root -> localGraphicsEnvironment (Win32GraphicsEnvironment) -> displayChanger (SunDisplayChanger) -> слушатели (Карта) -> key (D3DChachingSurfaceManager) -> bImg (BufferedImage)

Я мог бы изменить код фреймворка так, чтобы после каждого вызова BufferedImage.getGraphics () я сохранял ссылку на SurfaceManager BufferedImage. Затем я получаю localGraphicsEnvironment, приводим его к Win32GraphicsEnvironment, затем вызываю removeDisplayChangedListener (), используя ссылку на SurfaceManager объекта BufferedImage. Но я не думаю, что это правильный способ решения проблемы.

Может кто-нибудь помочь мне с этим вопросом? Большое спасибо!


БОЛЬШЕ ДЕТАЛЕЙ И НАХОДКИ

Компонент, который я пытаюсь добавить в свой пользовательский интерфейс, выполняет вызовы BufferedImage.getGraphics () каждый раз, когда он перерисовывается. В результате количество мусора, сохраняемого displayChanger (внутри SunGraphicsEnvironment ), должно увеличиваться по мере перекрашивания компонента.

Тем не менее, вещи ведут себя достаточно странно:

когда я посчитал свои действия на своем пользовательском интерфейсе, которые наверняка вызовут перерисовку, а затем проверил количество слушателей мусора внутри displayChanger по моему счету, они не совпадают. (Например, до моих кликов было 8 слушателей, и я сделал 60 щелчков. В конце концов, только 18 слушателей.)

С другой стороны, если я включаю точку останова и вступаю в процесс добавления элементов в displayListeners , каждый отдельный щелчок приводит к новой записи в displayListeners . И поэтому каждый BufferedImage, удерживаемый displayListeners , становится мусором.

Я рассмотрел возможность использования SurfaceManager, который используется в качестве ключа для displayListeners, для совместного использования или повторного использования, однако мой эксперимент исключил эту возможность. Я также рассматривал кеширование и намеренно предотвращал кеширование, делая каждый вызов для перерисовки уникальным. Тем не менее, я понятия не имею, как это могло произойти и как устранить утечку.

Ответы [ 2 ]

7 голосов
/ 05 июня 2010

После рендеринга BufferedImage вы должны вызвать dispose() в графическом контексте, возвращаемом createGraphics(). Вот пример и список подобных методов.

Добавление: это похоже на утечку объекта под названием packratting ; несоответствие слушателя звучит как артефакт использования отладчика. Вы можете получить некоторые идеи из статьи Устранение утечек памяти мягкими ссылками Брайана Гетца.

1 голос
/ 05 июня 2010

Попробуйте позвонить flush(), когда вам больше не нужно ваше изображение.

...