У меня проблема с некоторым 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, для совместного использования или повторного использования, однако мой эксперимент исключил эту возможность. Я также рассматривал кеширование и намеренно предотвращал кеширование, делая каждый вызов для перерисовки уникальным. Тем не менее, я понятия не имею, как это могло произойти и как устранить утечку.