Search code examples
javasocketsmemory-leaksbytearrayoutputstream

Java writing to ByteArrayOutputStream memory leak


I am writing bytes of image to ByteArrayOutputStream then sending it over socket. The problem is, when I do

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

Memory goes up VERY much, kinda memory leak.

I send using this

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);

As you can see I have tried all ways, the error comes when I write to the ByteArrayOutputStream, not when I transfer it. The receiver does not get any errors.

Any way I can clear the byteArray, and remove everything it has in it from memory? I know reset() does, but it dont in here. I want to dispose of the ByteArrayOutputStream directly when this is done.


Solution

  • @Christoffer Hammarström probably has the best solution, but I'll add this to try to explain the memory usage.

    These 2 lines are creating 3 copies of your image data:

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

    After executing this you have one copy of the data stored in image, one copy in the ByteArrayOutputStream and another copy in the byte array (toByteArray() does not return the internal buffer it creates a copy).

    Calling reset() does not release the memory inside the ByteArrayOutputStream, it just resets the position counter back to 0. The data is still there.

    To allow the memory to be released earlier you could assign each item to null as soon as you have finished with it. This will allow the memory to be collected by the garbage collector if it decides to run earlier. EG:

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