Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OutputStream OutOfMemoryError when sending HTTP

I am trying to publish a large video/image file from the local file system to an http path, but I run into an out of memory error after some time...

here is the code

public boolean publishFile(URI publishTo, String localPath) throws Exception {
    InputStream istream = null;
    OutputStream ostream = null;
    boolean isPublishSuccess = false;

    URL url = makeURL(publishTo.getHost(), this.port, publishTo.getPath());
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();


    if (conn != null) {

        try {

            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setRequestMethod("PUT");
            istream = new FileInputStream(localPath);
            ostream = conn.getOutputStream();

            int n;
            byte[] buf = new byte[4096];
            while ((n = istream.read(buf, 0, buf.length)) > 0) {
                ostream.write(buf, 0, n); //<--- ERROR happens on this line.......???
            }

            int rc = conn.getResponseCode();

            if (rc == 201) {
                isPublishSuccess = true;
            }

        } catch (Exception ex) {
            log.error(ex);
        } finally {
            if (ostream != null) {
                ostream.close();
            }

            if (istream != null) {
                istream.close();
            }
        }
    }

    return isPublishSuccess;

}

HEre is the error i am getting...

Exception in thread "Thread-8773" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:2786)
    at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:94)
    at sun.net.www.http.PosterOutputStream.write(PosterOutputStream.java:61)
    at com.test.HTTPClient.publishFile(HTTPClient.java:110)
    at com.test.HttpFileTransport.put(HttpFileTransport.java:97)
like image 734
ashchawla Avatar asked Jan 17 '10 18:01

ashchawla


People also ask

How do you fix OutOfMemoryError?

1) An easy way to solve OutOfMemoryError in java is to increase the maximum heap size by using JVM options "-Xmx512M", this will immediately solve your OutOfMemoryError.

What causes Java heap space error?

Java Heap space is one of the most common errors when it comes to memory handling in the Java Virtual Machine world. This error means that you tried to keep too much data on the heap of the JVM process and there is not enough memory to create new objects, and that the garbage collector can't collect enough garbage.


2 Answers

The HttpUrlConnection is buffering the data so that it can set the Content-Length header (per HTTP spec).

One alternative, if your destination server supports it, is to use "chunked" transfers. This will buffer only a small portion of data at a time. However, not all services support it (Amazon S3, for example, doesn't).

Another alternative (and imo a better one) is to use Jakarta HttpClient. You can set the "entity" in a request from a file, and the connection code will set request headers appropriately.


Edit: nos commented that the OP could call HttpURLConnection.setFixedLengthStreamingMode(long length). I was unaware of this method; it was added in 1.5, and I haven't used this class since then.

However, I still suggest using Jakarta HttpClient, for the simple reason that it reduces the amount of code that the OP has to maintain. Code that is boilerplate, yet still has the potential for errors:

  • The OP correctly handles the loop to copy between input and output. Usually when I see an example of this, the poster either doesn't properly check the returned buffer size, or keeps re-allocating the buffers. Congratulations, but you now have to ensure that your successors take as much care.
  • The exception handling isn't quite so good. Yes, the OP remembers to close the connections in a finally block, and again, congratulations on that. Except that either of the close() calls could throw IOException, keeping the other from executing. And the method as a whole throws Exception, so that the compiler isn't going to help catch similar errors.
  • I count 31 lines of code to setup and execute the response (excluding the response code check and the URL computation, but including the try/catch/finally). With HttpClient, this would be somewhere in the range of a half dozen LOC.

Even if the OP had written this code perfectly, and refactored it into methods similar to those in Jakarta Commons IO, s/he shouldn't do that. This code has been written and tested by others. I know that it's a waste of my time to rewrite it, and suspect that it's a waste of the OP's time as well.

like image 147
kdgregory Avatar answered Nov 05 '22 04:11

kdgregory


conn.setFixedLengthStreamingMode((int) new File(localpath).length());

And for buffering you could cover your streams into the BufferedOutputStream and BufferedInputStream

Good example of chunked uploading you could find there: gdata-java-client

like image 5
Alexandr Avatar answered Nov 05 '22 03:11

Alexandr