【问题标题】:Java writing to ByteArrayOutputStream memory leakJava 写入 ByteArrayOutputStream 内存泄漏
【发布时间】:2012-08-15 14:04:27
【问题描述】:

我正在将图像字节写入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

【问题讨论】:

  • image有哪些属性?尺寸、颜色模型等?
  • 你用多少内存运行它?你的虚拟机设置?图片有多大?
  • 您真的在ImageIO.write(...) 上收到OutOfMemoryError 吗?
  • 用相同的信息问同样的问题overover 不太可能得到更好的答案,而且会浪费大家的时间。如果您想要真正的答案,请发布您的整个程序,以便任何想要帮助的人都可以编译并运行它。如果您的程序太大而无法发布整个内容,请将其削减,直到您可以发布它并且仍然显示行为。
  • 写“错误来了”而不提供实际的堆栈跟踪至少是没用的......

标签: java sockets memory-leaks bytearrayoutputstream


【解决方案1】:

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

这两行将创建 3 个图像数据副本:

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

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

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

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

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

【讨论】:

    【解决方案2】:

    为什么你必须摆弄发送缓冲区的大小?你在这个套接字上使用什么样的协议?它应该很简单:

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

    如果你必须使用ByteArrayOutputStream,至少使用

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

    这样您就不会产生多余的byte[]

    【讨论】:

      【解决方案3】:

      这不是您想要的答案,但您可能希望考虑一下。

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

      【讨论】:

        【解决方案4】:

        您可以通过System.gc() 请求虚拟机运行垃圾回收,但这并不保证会实际发生。虚拟机在认为有必要或适当的时候执行垃圾回收。

        【讨论】:

        • 我在我的代码末尾做。帮不上忙。我处置并清空对象和所有这些,但它仍然留在内存中。
        • 仅仅因为你丢弃了它,并不意味着内存立即被释放。由 VM 决定何时释放内存。
        【解决方案5】:

        你所描述的很正常。它必须将您正在创建的图像的字节放在某处。

        您可以使用 FileOutputStream 代替内存来写入字节。然后,您必须创建一个 FileInputStream 以从您写入的文件中读取数据,并创建一个循环,将字节读入一个 64k 大小的字节数组缓冲区,然后将这些字节写入连接的输出流。

        你提到了错误。如果您收到错误,那是什么错误?

        如果您使用客户端 JVM(java 的 -client 参数),那么内存可能会返回给操作系统,Java 进程将再次缩小。我不确定。

        如果您不喜欢 JAI 使用的内存量,可以尝试使用 Sanselan:http://commons.apache.org/imaging/

        【讨论】:

          猜你喜欢
          • 2012-08-11
          • 1970-01-01
          • 1970-01-01
          • 2016-09-29
          • 2015-08-14
          • 2015-12-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多