4

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.

posdef
  • 6,498
  • 11
  • 46
  • 94
  • Which properties does `image`have? Dimensions, color model etc.? – lost Aug 15 '12 at 14:21
  • how much memory you are running this with? your VM settings? and how big is the image? – Ravi Bhatt Aug 15 '12 at 14:21
  • Are you actually getting an `OutOfMemoryError` on the `ImageIO.write(...)`? – Christoffer Hammarström Aug 15 '12 at 15:11
  • 2
    Asking the same question [over](http://stackoverflow.com/questions/11957981/java-bufferedarrayoutputstream-leaks-in-memory) and [over](http://stackoverflow.com/questions/11956377/java-sockets-everything-written-stays-in-memory) with the same information is unlikely to get you better answers, and wastes everyone's time. If you want real answers, *post your entire program*, so that anybody who wants to help can compile it and run it. If your program is too big to post the whole thing, cut it down until you can post it and still show the behavior. – kdgregory Aug 15 '12 at 15:26
  • It looks like what you are really asking is this: "Why is the java memory increasing so much and what can I do to avoid this?" – Sarel Botha Aug 15 '12 at 16:07
  • 1
    Writing "the error comes" without providing the actual stack trace is useless at least... – Nikem Aug 16 '12 at 07:39

5 Answers5

6

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[].

Christoffer Hammarström
  • 27,242
  • 4
  • 49
  • 58
6

@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;
...
Aaron
  • 5,931
  • 4
  • 27
  • 31
1

This is not quite the answer you want, but something you might wish to consider.

Why not create a pool of byte arrays and resuse them everytime you need to. This will be a little more efficient as you wont be creating new arrays and throwing them away all the time. Using less gc is always a good thing. You will also be able to guarantee that the application has enough memory to operate in all the time.

theINtoy
  • 3,388
  • 2
  • 37
  • 60
0

You can request that the VM to run garbage collection through System.gc() but this is NOT guaranteed to actually happen. The virtual machine performs garbage collection when it decides it is necessary or is an appropriate time.

Kevin Mangold
  • 1,167
  • 8
  • 21
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/

Sarel Botha
  • 12,419
  • 7
  • 54
  • 59