BufferedImage.getGraphics()导致内存泄漏,是否已解决? - java

我在某些框架API调用BufferedImage.getGraphics()方法时遇到问题,从而导致内存泄漏。此方法的作用是始终调用BufferedImage.createGraphics()。在Windows计算机上,createGraphics()由Win32GraphicsEnvironment处理,该方法将侦听器列表保留在其字段displayChanger中。当我在BufferedImage someChart上调用getGraphics时,会将someChart的SurfaceManager(保留对someChart的引用)添加到Win32GraphicsEnvironment中的侦听器映射中,以防止对someChart进行垃圾收集。之后,什么也没有从侦听器映射中删除someChart的SurfaceManager。

通常,一旦调用getGraphics,阻止BufferedImage被垃圾回收的汇总路径如下:

GC根目录-> localGraphicsEnvironment(Win32GraphicsEnvironment)
-> displayChanger(SunDisplayChanger)->侦听器(Map)->键(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都变成垃圾。

我认为用作displayListeners密钥的SurfaceManager可以共享或重用,但我的实验排除了这种可能性。我还考虑了缓存,并通过使每个重绘调用都唯一,从而故意防止了缓存的发生。不过,我不知道这种情况如何发生以及如何解决泄漏。

参考方案

渲染BufferedImage后,应在dispose()返回的图形上下文上调用 createGraphics() 。这是类似方法的example和list。

附录:这似乎是一个称为packratting的对象泄漏;侦听器不匹配听起来像是使用调试器的产物。您可能会从Brian Goetz的Plugging memory leaks with soft references文章中得到一些想法。

Java-通过套接字发送指向BufferedImage的对象 - java

我和一群朋友正在用Java开发项目,我们需要一些有关通过套接字发送对象的帮助。到目前为止,我们已经实现了使用ObjectOutputStream和ObjectInputStream通过套接字发送简单对象(int,字符串和诸如此类)的方法。但是,我们今天遇到了一个大问题(无论如何对我们来说都是巨大的^^)我们有一个树状结构,需要从一台PC发送到另一台PC。问题…

Java:正则表达式模式匹配器是否有大小限制? - java

我的模式类似于OR:“word1 | word2 | word3”我大约有800个字。可能有问题吗? 参考方案 您仅受记忆和理智的限制。 :)

在Java中将数组转换为bufferedimage的困难 - java

我想在Java中逐个像素地处理图像,因此我建立了一个一维列表,其中包含我的颜色。然后,我将其转换为缓冲图像,但是像素全都错了。因此,我将其简化为下面的绝对基础知识。在我看来,这应该给一个正方形,左半边是蓝色,右半边是黑色。相反,它会给出蓝色和黑色的斜条纹。有什么想法吗? private void create(){ int w = 100; int h = …

Java:线程池如何将线程映射到可运行对象 - java

试图绕过Java并发问题,并且很难理解线程池,线程以及它们正在执行的可运行“任务”之间的关系。如果我创建一个有10个线程的线程池,那么我是否必须将相同的任务传递给池中的每个线程,或者池化的线程实际上只是与任务无关的“工人无人机”可用于执行任何任务?无论哪种方式,Executor / ExecutorService如何将正确的任务分配给正确的线程? 参考方案 …

JAVA:字节码和二进制有什么区别? - java

java字节代码(已编译的语言,也称为目标代码)与机器代码(当前计算机的本机代码)之间有什么区别?我读过一些书,他们将字节码称为二进制指令,但我不知道为什么。 参考方案 字节码是独立于平台的,在Windows中运行的编译器编译的字节码仍将在linux / unix / mac中运行。机器代码是特定于平台的,如果在Windows x86中编译,则它将仅在Win…