Could this unclosed() byteArrayInputStream cause high Heap usage ?

K

Krist

Hi all,

As part of our reporting integrated with our JSF/JSP application, the
report is converted to PDF then sent to browser for user to display.
mean while during peak load our Heap usage could reach 3.5GB - 4GB. So
I am suspecting the unclosed byteArrayInputStream is the cause.
(This is a production application so I am collecting information
before change the code)

Is the unclosed() byteArrayInputStream really cause the problem ?
(the codes is below)

Thank you,
Krist



ByteArrayInputStream byteArrayInputStream = (ByteArrayInputStream)

reportClientDoc.getPrintOutputController().export(exportOptions);
reportClientDoc.close();
writeToBrowser(byteArrayInputStream, response, "application/csv",
EXPORT_FILE);

private void writeToBrowser(ByteArrayInputStream byteArrayInputStream,
HttpServletResponse
response, String mimetype, String exportFile)
throws Exception {
byte[] buffer = new byte[byteArrayInputStream.available()];
int bytesRead = 0;
response.reset();
response.setHeader("Content-disposition", "inline;filename=" +
exportFile);
response.setContentType(mimetype);
//Stream the byte array to the client.
while((bytesRead = byteArrayInputStream.read(buffer)) != -1)
{ response.getOutputStream().write(buffer , 0,
bytesRead);}

//Flush and close the output stream.
response.getOutputStream().flush();
response.getOutputStream().close();
}
 
R

Roedy Green

Is the unclosed() byteArrayInputStream really cause the problem ?

It is a big array of characters that holds the entire stream. How
much of a problem it is unclosed depends on how big the stream it
holds is. It is just a StringBuilder in disguise. Is there any reason
you would NOT close the stream?
--
Roedy Green Canadian Mind Products
http://mindprod.com

You can’t have great software without a great team, and most software teams behave like dysfunctional families.
~ Jim McCarthy
 
L

Lew

Roedy Green wrote:
Krist wrote, quoted or indirectly quoted someone who said :
Based on my reading of the Javadocs (what is yours?), I'd say not.
It is a big array of characters that holds the entire stream. How
much of a problem it is unclosed depends on how big the stream it
holds is. It is just a StringBuilder in disguise. Is there any reason
you would NOT close the stream?

Maybe this, from the Javadocs for 'ByteArrayInputStream' (what a funny place
to look for information about 'ByteArrayInputStream'!):
<http://java.sun.com/javase/6/docs/api/java/io/ByteArrayInputStream.html#close()>
"Closing a ByteArrayInputStream has no effect."
 
K

Kevin McMurtrie

Krist said:
Hi all,

As part of our reporting integrated with our JSF/JSP application, the
report is converted to PDF then sent to browser for user to display.
mean while during peak load our Heap usage could reach 3.5GB - 4GB. So
I am suspecting the unclosed byteArrayInputStream is the cause.
(This is a production application so I am collecting information
before change the code)

Is the unclosed() byteArrayInputStream really cause the problem ?
(the codes is below)

Thank you,
Krist



ByteArrayInputStream byteArrayInputStream = (ByteArrayInputStream)

reportClientDoc.getPrintOutputController().export(exportOptions);
reportClientDoc.close();
writeToBrowser(byteArrayInputStream, response, "application/csv",
EXPORT_FILE);

private void writeToBrowser(ByteArrayInputStream byteArrayInputStream,
HttpServletResponse
response, String mimetype, String exportFile)
throws Exception {
byte[] buffer = new byte[byteArrayInputStream.available()];
int bytesRead = 0;
response.reset();
response.setHeader("Content-disposition", "inline;filename=" +
exportFile);
response.setContentType(mimetype);
//Stream the byte array to the client.
while((bytesRead = byteArrayInputStream.read(buffer)) != -1)
{ response.getOutputStream().write(buffer , 0,
bytesRead);}

//Flush and close the output stream.
response.getOutputStream().flush();
response.getOutputStream().close();
}

This probably isn't where your memory is going. Turn on object
histogram dumps then send a QUIT signal when memory is high.

On the other hand, the code is bad:

Casting the InputStream to an implementation is prone to failure. Don't.

byte[] buffer = new byte[byteArrayInputStream.available()];

InputStream.available() returns a value between 0 and the entire size of
the data. It's for avoiding blocking I/O and aligning buffers. It's
not for setting up a constant buffer size. In the case of
ByteArrayInputStream, it's the entire size of the data. Another
implementation might return zero and then you'd infinite loop. Use a
constant, like 2048 for WAN or 65536 for LAN.

If the PrintOutputController belongs to you, consider modifying it to
write directly to an OutputStream. This will eliminate intermediate
buffering and provide a faster first-byte response. The downside is
that the PrintOutputController could be active and holding resources for
a very long time if the client is on dialup. Which is best depends on
the application.
 
K

Krist

 Krist said:
As part of our reporting integrated with our JSF/JSP application, the
report is converted to PDF then sent to browser for user to display.
mean while during peak load our Heap usage could reach 3.5GB - 4GB. So
I am suspecting the unclosed byteArrayInputStream is the cause.
(This is a production application so I am collecting information
before change the code)
Is the unclosed() byteArrayInputStream  really cause the problem ?
(the codes is below)
Thank you,
Krist
ByteArrayInputStream byteArrayInputStream = (ByteArrayInputStream)
reportClientDoc.getPrintOutputController().export(exportOptions);
reportClientDoc.close();
writeToBrowser(byteArrayInputStream, response, "application/csv",
EXPORT_FILE);
private void writeToBrowser(ByteArrayInputStream byteArrayInputStream,
HttpServletResponse
response, String mimetype, String exportFile)
   throws Exception {
      byte[] buffer = new byte[byteArrayInputStream.available()];
      int bytesRead = 0;
      response.reset();
      response.setHeader("Content-disposition", "inline;filename=" +
exportFile);
      response.setContentType(mimetype);
      //Stream the byte array to the client.
      while((bytesRead = byteArrayInputStream.read(buffer)) != -1)
            { response.getOutputStream().write(buffer , 0,
bytesRead);}
      //Flush and close the output stream.
      response.getOutputStream().flush();
      response.getOutputStream().close();
   }

This probably isn't where your memory is going.  Turn on object
histogram dumps then send a QUIT signal when memory is high.

On the other hand, the code is bad:

Casting the InputStream to an implementation is prone to failure.  Don't.

  byte[] buffer = new byte[byteArrayInputStream.available()];

InputStream.available() returns a value between 0 and the entire size of
the data.  It's for avoiding blocking I/O and aligning buffers.  It's
not for setting up a constant buffer size.  In the case of
ByteArrayInputStream, it's the entire size of the data.  Another
implementation might return zero and then you'd infinite loop.  Use a
constant, like 2048 for WAN or 65536 for LAN.

If the PrintOutputController belongs to you, consider modifying it to
write directly to an OutputStream.  This will eliminate intermediate
buffering and provide a faster first-byte response.  The downside is
that the PrintOutputController could be active and holding resources for
a very long time if the client is on dialup.  Which is best depends on
the application.

Hi sir,

When will the memory taken by the byteArrayInputStream will be
released ?
Will it be garbage collected ?

Thanks,
Krist
 
R

Roedy Green

When will the memory taken by the byteArrayInputStream will be
released ?
Will it be garbage collected ?

You would have to check the ByteArrayInputStream constructor source to
see if it makes a private copy of the byte array.

Presuming it does, the array would be GCed when there are no more
references to the BAOS.

Presuming it does not, the array would be GCed where there are no more
references to the BAOS, and no more reference to the original byte
array.
 
E

EJP

InputStream.available() returns a value between 0 and the entire size of
the data.

It returns the number of bytes that can be read without blocking, or
zero in some implementations (e.g. SSLSocket). A practically useless
feature. Use a standard size buffer like 4k, 8k etc.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top