Question

I'm having some troubles with downloading files on some devices, I get OOM error. Here is the code that I used to download large files:

/**
 * The size of the chunks that an file is split when writing to server.<br />
 * 1024 * 1024 -> 1mb
 */
private static final int CHUNK_SIZE = 1024 * 1024;

File output = new File(sdCardPath, fileName);
FileOutputStream fileOutputStream = null;
try {
fileOutputStream = new FileOutputStream(output);
} catch (FileNotFoundException e) {
e.printStackTrace();
}

int offset = 0;

// compute the number of chunks of 1 mb for downloading the file
// by parts
int parts = tmpFileSize / CHUNK_SIZE;
ByteString readingfile = null;
long progressUpdate = 0;

for (int partsCounter = 0; partsCounter < parts + 1; partsCounter++) {
    try {
        readingfile = serviceApi
                .readFile(
                        session,
                        filehandle, offset, CHUNK_SIZE);

        byte[] bytesRead = readingfile.toByteArray();
        int numberOfBytesReaded = bytesRead.length;
        offset = offset + numberOfBytesReaded;
        progress.publish(""
                + (int) ((progressUpdate * 100) / tmpFileSize));
        progressUpdate += numberOfBytesReaded;
        fileOutputStream.write(bytesRead, 0,
                numberOfBytesReaded);

    } catch (IOException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

try {
    if (null != fileOutputStream) {
        fileOutputStream.flush();
        fileOutputStream.close();
    }
} catch (IOException e) {
    e.printStackTrace();
}

Can someone let me know if I'm doing something wrong here ? Thank you.


Solution based on @Ari answer I've updated the code. Now it is optimized to use only 1mb (I don't know if it is the best way to split the process in chunks but it seems to be improved now and it doesn't give OOM). I will try and further optimize it by detecting how much heap memory I can use, but I'm not sure I can achieve this. Until than this seems to be the best option. Thank you again @Ari.

Was it helpful?

Solution

You have many buffers you don't need.

  1. byte[] br = readingfile.toByteArray(); you are using to get numberOfBytesReaded.
  2. Then you are getting array again: inputStream = ... readingfile.toByteArray()); And copy it to third buffer
  3. byte data[] = new byte[bufferSize];.

Try to use just one for all of these operations.

General advice is to set pointers of objects (and arrays) to NULL when you don't need them anymore.

I would use code like this:

for (int partsCounter = 0; partsCounter < parts + 1; partsCounter++) {
    readingfile = serviceApi.readFile(session, filehandle, offset,
            (int) bufferSize);
    byte[] br = readingfile.toByteArray();
    int numberOfBytesReaded = br.length;
    offset = offset + numberOfBytesReaded;

    try {
            progress.publish(""
                    + (int) ((progressUpdate * 100) / tmpFileSize));
            progressUpdate += numberOfBytesReaded;
            fileOutputStream.write(br, 0, numberOfBytesReaded);
        }
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top