我遇到一些框架API调用Buffered
Image.getGraphics()方法的问题,从而导致内存泄漏.这个方法的作用是它总是调用BufferedImage.createGraphics().在
Windows机器上,createGraphics()由Win32GraphicsEnvironment处理,它将侦听器列表保存在其字段displayChanger中.当我在BufferedImage someChart上调用getGraphics时,someChart的SurfaceManager(保留对someChart的引用)被添加到Win32GraphicsEnvironment中的侦听器映射中,从而防止someChart被垃圾收集.之后没有任何东西从侦听器地图中删除someChart的SurfaceManager.
通常,一旦调用getGraphics,阻止BufferedImage被垃圾收集的汇总路径如下:
GC Root – > localGraphicsEnvironment(Win32GraphicsEnvironment)
– > displayChanger(SunDisplayChanger) – >听众(地图) – > key(D3DChachingSurfaceManager) – > BIMG(BufferedImage的)
我本可以更改框架的代码,以便在每次调用BufferedImage.getGraphics()之后,我保留对BufferedImage的SurfaceManager的引用.然后,我获取localGraphicsEnvironment,将其强制转换为Win32GraphicsEnvironment,然后使用对BufferedImage的SurfaceManager的引用调用removeDisplayChangedListener().但我不认为这是解决问题的正确方法.
有人可以帮我解决这个问题吗?非常感谢!
更多细节和发现
我试图添加到我的UI的组件每次重新绘制时都会调用BufferedImage.getGraphics().因此,当组件重新绘制时,保留在displayChanger(在SunGraphicsEnvironment内部)的垃圾数量应该会增加.
然而,事情表现得非常奇怪:
当我在我的UI上计算我的操作肯定会触发重绘时,然后检查displayChanger中的垃圾监听器的数量与我的计数,它们不匹配. (例如,在点击之前有8位听众,我点击了60次.毕竟,只有18位听众.)
另一方面,如果我打开断点,并进入向displayListeners添加内容的过程,则每次单击都会在displayListeners中生成一个新条目.因此,displayListeners持有的每个BufferedImage都会变成垃圾.
我考虑过可以共享或重用SurfaceManager(可用作displayListeners的键)的可能性,但我的实验排除了这种可能性.我也考虑过缓存,我故意通过每次调用重绘独特的方式来防止缓存发生.不过,我不知道如何发生这种情况以及如何解决泄漏问题.