2

I am trying to read a 2mb file into a memory and then send that file to web server. But I am getting out of memory exception.

         FileConnection fileConn = (FileConnection)Connector.open("file:///" + pictureURI.getString(), Connector.READ);
     InputStream fis = fileConn.openInputStream();
     long overallSize = fileConn.fileSize();

     int chunkSize = 2048;
     int length = 0;
     while (length < overallSize)
     {

        byte[] data = new byte[chunkSize];
        int readAmount = fis.read(data, 0, chunkSize);
        byte[] newImageData = new byte[rawImage.length + chunkSize];
        System.arraycopy(rawImage, 0, newImageData, 0, length);
        System.arraycopy(data, 0, newImageData, length, readAmount);
        rawImage = newImageData;
        length += readAmount;

     }
       fis.close();
        fileConn.close(); 

500kb files are uploading. What could be the reason? Please shed a light on this.

I tried this also in loop but no use, System.gc();

[EDIT] https://stackoverflow.com/users/45668/malcolm has put me on right track. Now I struck here

  this.progress = progress;

  HttpConnection conn = null;
  OutputStream os = null;
  InputStream s = null;
  StringBuffer responseString = new StringBuffer();

  try
  {
     System.out.println(System.getProperty("HTTPClient.dontChunkRequests"));
     conn = (HttpConnection)Connector.open(url);
     //conn.setRequestProperty("User-Agent", "Profile/MIDP-2.1 Configuration/CLDC-1.1");
     conn.setRequestMethod(HttpConnection.POST);

     // The messages
     conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=---------------------------4664151417711");
     conn.setRequestProperty("Content-Length", "355");

     os = conn.openOutputStream();

     System.out.println("file name at upload " + fileName);
     String message1 = "";
     message1 += "-----------------------------4664151417711\r\n";
     message1 += "Content-Disposition: form-data; name=\"file\"; filename=\"" + fileName + "\"\r\n";
     message1 += "Content-Type: image/gif\r\n";
     message1 += "\r\n";

     os.write(message1.getBytes());

     System.gc();

     // Send the image
     int index = 0;
     int size = 2048;
     double progdouble;
     do
     {
        progdouble = ((double)index) / ((double)rawImage.length) * 100;
        progress.setValue((int)progdouble);

        if((index+size) > rawImage.length)
        {
           size = rawImage.length - index;
        }
        os.write(rawImage, index, size);
        index += size;

        System.gc();
     } while(index < rawImage.length);

     String message2 = "\r\n-----------------------------4664151417711\r\n";
     message2 += "Content-Disposition: form-data; name=\"number\"\r\n\r\n";
     message2 += this.user_phone_number;         

     os.write(message2.getBytes());

     String message3 = "\r\n-----------------------------4664151417711\r\n";
     message3 += "Content-Disposition: form-data; name=\"uuid\"\r\n\r\n";
     message3 += this.user_uuid;         

     os.write(message3.getBytes());

     String message4 = "\r\n-----------------------------4664151417711--\r\n";  

     os.write(message4.getBytes());


     os.flush();
     os.close();

     // Read

     s = conn.openInputStream();
     int ch, i = 0, maxSize = 16384;
     while(((ch = s.read())!= -1 ) & (i++ < maxSize)) 
     {
        responseString.append((char) ch);
     }

     conn.close();
     System.out.println("response =>"+responseString.toString());



     return responseString.toString();
  }
  catch (IOException ioe)
  {
     return ioe.toString();
  }

Now its failing here..

[EDIT2]

// algorithm that will read 1024 bytes at a time 
        byte b[] = new byte[chunkSize];
        for (int i = 0; i < overallSize; i += chunkSize) { 

            if ((i + chunkSize) < overallSize) {
                fis.read(b, 0, chunkSize);
            } else {
                int left = (int)overallSize - i;
                fis.read(b, 0, left);
            }

            // writing into the output stream - ( these lines will cause the "memory leak", without these, it will not happen)
            os.write(b);
            System.gc(); 

            progdouble = ((double)i) / ((double)overallSize) * 100;
            progress.setValue((int)progdouble); 
        }
        os.flush();

Thanks in advance.

Community
  • 1
  • 1
Venu
  • 7,243
  • 4
  • 39
  • 54

2 Answers2

3

Your mobile (Nokia x2-01 specs) is limited to 2Mb of heap space for the whole app. Design your app according to these limitations. 2Mb bytearray in memory at once - no way.

IrLED
  • 438
  • 2
  • 5
3

You allocate a lot of new arrays along the way, which is totally unnecessary. Each new byte[] line allocates a new array.

You should read into one large array, and you should allocate it once, before the loop. You can easily do this since you know the exact size of the file. The code will look something like this:

FileConnection fileConn;
InputStream is;

try {
    fileConn = (FileConnection) Connector.open("file:///" + pictureURI.getString(), Connector.READ);
    is = fileConn.openInputStream();

    long overallSize = fileConn.fileSize();
    if (overallSize > Integer.MAX_VALUE) throw new IllegalArgumentException("File is too large);
    byte[] imageData = new byte[(int) overallSize];
    int chunkSize = 2048;
    int bytesReadTotal = 0;
    while (bytesRead < overallSize) {
        int bytesRead = is.read(imageData, bytesReadTotal, Math.min(imageData.length - bytesReadTotal, chunkSize));
        if (bytesRead == -1) break;
        bytesReadTotal += bytesRead;
    }
} finally {
    if (is != null) is.close();
    if (fileConn != null) fileConn.close();
}
Malcolm
  • 41,014
  • 11
  • 68
  • 91
  • Thanks for the reply. I will check this and get back to you soon. – Venu Mar 08 '12 at 15:27
  • You put on right track. Now I am able to move forward from reading file, but getting same error while uploading... Please kindly have a look at this code. – Venu Mar 08 '12 at 15:51
  • files reading is fine now, but when I try to upload it giving me same error. Is it a good method to read a data in to an array and then flush it out or read and push instantly is a better one? – Venu Mar 09 '12 at 07:55
  • 1
    @VenuGopalT If you only want to send a file, it makes sense, of course, not to load the whole file to the memory, but to use a small buffer instead. You read a portion of data into it, send it, then repeat these steps until the whole file is sent. – Malcolm Mar 09 '12 at 08:47
  • I tried this method, but still failing after 60% of upload. Seems like this device (Nokia x2-01) won't support this size. I checked other video uploads apps which has same issue. – Venu Mar 09 '12 at 11:04
  • @VenuGopalT I hope you don't create a new array during each loop iteration? The method I described doesn't consume any memory in your code at all inside the loop itself. If it still fails, then there is a problem with the streams implementation on this JVM, you can't do much in this case. – Malcolm Mar 09 '12 at 11:07
  • I didn't create array in the loop. For just reference, I posted the code above. Please check it once, whether something I can do? – Venu Mar 09 '12 at 11:12
  • @VenuGopalT No, I don't think so, unfortunately. This is something internal to the JVM, as it appears. – Malcolm Mar 09 '12 at 11:19