3

我正在写入图像字节ByteArrayOutputStream然后通过套接字发送它。问题是,当我这样做时

ImageIO.write(image, "gif", byteArray);

内存上升非常多,有点内存泄漏。

我用这个发送

ImageIO.write(image, "gif", byteArrayO);         
byte [] byteArray = byteArrayO.toByteArray();
byteArrayO.flush();
byteArrayO.reset();
Connection.pw.println("" + byteArray.length);
int old = Connection.client.getSendBufferSize();
Connection.client.setSendBufferSize(byteArray.length);
Connection.client.getOutputStream().write(byteArray, 0, byteArray.length);
Connection.client.getOutputStream().flush();
image.flush();
image = null;
byteArrayO = null;
byteArray = null;
System.gc();
Connection.client.setSendBufferSize(old);

如您所见,我已经尝试了所有方法,当我写入时出现错误ByteArrayOutputStream,而不是在传输时出现。接收器没有收到任何错误。

有什么办法可以清除 byteArray,并从内存中删除其中的所有内容?我知道reset()有,但这里没有。我想在ByteArrayOutputStream完成后直接处理掉。

4

5 回答 5

5

Why do you have to fiddle with the send buffer size? What kind of protocol are you using on top of this socket? It should be just as simple as:

ImageIO.write(image, "gif", Connection.client.getOutputStream());

If you have to use a ByteArrayOutputStream, at least use

byteArrayO.writeTo(Connection.client.getOutputStream())

so you don't make an extra redundant byte[].

于 2012-08-15T14:56:10.980 回答
5

@Christoffer Hammarström 可能有最好的解决方案,但我会添加它以尝试解释内存使用情况。

这 2 行正在创建图像数据的 3 个副本:

ImageIO.write(image, "gif", byteArrayO);
byte [] byteArray = byteArrayO.toByteArray(); 

执行此操作后,您将获得一份存储在图像中的数据副本,一份在 ByteArrayOutputStream 中,另一份在字节数组中(toByteArray() 不返回它创建副本的内部缓冲区)。

调用 reset() 不会释放 ByteArrayOutputStream 内的内存,它只是将位置计数器重置为 0。数据仍然存在。

为了允许更早地释放内存,您可以在完成每个项目后立即将其分配为 null。如果垃圾收集器决定提前运行,这将允许内存被垃圾收集器收集。例如:

ImageIO.write(image, "gif", byteArrayO);
image = null;
byte [] byteArray = byteArrayO.toByteArray(); 
byteArrayO = null;
...
于 2012-08-15T15:10:05.487 回答
1

这不是您想要的答案,而是您可能希望考虑的问题。

为什么不创建一个字节数组池并在每次需要时重新使用它们。这将更有效率,因为您不会一直创建新数组并将它们丢弃。使用更少的 gc 总是一件好事。您还可以保证应用程序有足够的内存来一直运行。

于 2012-08-15T14:50:50.320 回答
0

What you are describing is pretty normal. It has to put the bytes of the image you are creating somewhere.

Instead of memory you can use a FileOutputStream to write the bytes to. You then have to make a FileInputStream to read from the file you wrote to and a loop which reads bytes into a byte array buffer of say 64k size and then writes those bytes to the connection's output stream.

You mention error. If you are getting an error what is the error?

If you use the client JVM (-client argument to java) then the memory might be given back to the OS and the Java process will shrink again. I'm not sure about this.

If you don't like how much memory JAI is using you can try using Sanselan: http://commons.apache.org/imaging/

于 2012-08-15T14:56:25.703 回答
0

您可以请求虚拟机运行垃圾收集,System.gc()但这不能保证实际发生。虚拟机在确定有必要或适当的时候执行垃圾收集。

于 2012-08-15T14:07:40.983 回答