out of memory Error while writing ByteArrayOutputStream in Android

11,309

Solution 1

What you are doing isn't practical, but the way to do it is as follows:

File file = new File("/sdcard/E0022505.mp4");
try {
       is = new FileInputStream(file);
} catch (FileNotFoundException e2) {
       e2.printStackTrace();
}
byte[] fileData = new byte[file.length()];
int read = 0;
while(read != fileData.length) {
   read += is.read(fileData, read, fileData.length - read);
}
//fileData now has all of the files bytes (don't forget to close is)

Solution 2

If you know how big your file is going to be, you'd probably want to seed the bytearrayoutputstream to that size (or slightly larger) in the constructor. I'm not 100% sure of the details, but I think BAOS creates a new array, and copies the old one in, each time 'expand' is called. Other implementations keep a list of arrays that are rebuilt when outputting. Either way, you don't want that (doubles memory usage, or worse).

new ByteArrayOutputStream(new File(Environment.getExternalStorageDirectory(), "E0022505.mp4").length());
Share:
11,309
Sanat Pandey
Author by

Sanat Pandey

Updated on July 14, 2022

Comments

  • Sanat Pandey
    Sanat Pandey almost 2 years

    I have a big problem, that I am reading 2^21 bytes from a video file which resides in Sdcard but when we write the same in ByteArrayOutputStream it throws an Exception as Out of Memory. I don't know why? Please suggest the right solution for the same.

    Here is the stack trace.

    Error Stack:

    11-03 19:24:23.193: ERROR/AndroidRuntime(28258): FATAL EXCEPTION: main
    11-03 19:24:23.193: ERROR/AndroidRuntime(28258): java.lang.OutOfMemoryError
    11-03 19:24:23.193: ERROR/AndroidRuntime(28258):     at java.io.ByteArrayOutputStream.expand(ByteArrayOutputStream.java:93)
    11-03 19:24:23.193: ERROR/AndroidRuntime(28258):     at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:218)
    11-03 19:24:23.193: ERROR/AndroidRuntime(28258):     at com.example.TestCryptoActivity.onCreate(TestCryptoActivity.java:42)
    11-03 19:24:23.193: ERROR/AndroidRuntime(28258):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
    11-03 19:24:23.193: ERROR/AndroidRuntime(28258):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
    11-03 19:24:23.193: ERROR/AndroidRuntime(28258):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
    11-03 19:24:23.193: ERROR/AndroidRuntime(28258):     at android.app.ActivityThread.access$2300(ActivityThread.java:125)
    11-03 19:24:23.193: ERROR/AndroidRuntime(28258):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
    11-03 19:24:23.193: ERROR/AndroidRuntime(28258):     at android.os.Handler.dispatchMessage(Handler.java:99)
    11-03 19:24:23.193: ERROR/AndroidRuntime(28258):     at android.os.Looper.loop(Looper.java:123)
    11-03 19:24:23.193: ERROR/AndroidRuntime(28258):     at android.app.ActivityThread.main(ActivityThread.java:4627)
    11-03 19:24:23.193: ERROR/AndroidRuntime(28258):     at java.lang.reflect.Method.invokeNative(Native Method)
    11-03 19:24:23.193: ERROR/AndroidRuntime(28258):     at java.lang.reflect.Method.invoke(Method.java:521)
    11-03 19:24:23.193: ERROR/AndroidRuntime(28258):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
    11-03 19:24:23.193: ERROR/AndroidRuntime(28258):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
    11-03 19:24:23.193: ERROR/AndroidRuntime(28258):     at dalvik.system.NativeStart.main(Native Method)
    

    Code:

    try {
        is = new FileInputStream("/sdcard/E0022505.mp4");
    } catch (FileNotFoundException e2) {
        // TODO Auto-generated catch block
        e2.printStackTrace();
    }
    
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    byte[] b = new byte[1024];
    try {
        while ((bytesRead  = is.read(b)) != -1) {
            bos.write(b, 0, bytesRead);//--------This position returns the same error
        }
    } catch (IOException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
    
    byte[] bytes = bos.toByteArray();
    try {
        String byteString = new String(bytes,"UTF-8");
        System.out.println("the bytes array of video:"+byteString);
    } catch (UnsupportedEncodingException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
    
  • Yar
    Yar over 9 years
    Sorry, but how is this supposed to fix OutOfMemoryError if you actually declare: byte[] fileData = new byte[file.length()]; so you load WHOLE FILE to memory?
  • Justin Breitfeller
    Justin Breitfeller over 9 years
    Well this approach doesn't attempt to allocate another 2MB block as a string. But in general (and as I indicated in my answer) you want to avoid doing this if you can as it isn't practical. In his case, I assume there was a reason he wanted to load the entire file into memory. That really wasn't indicated here. I'm sure he figured this out 3 years ago though so its all really moot.
  • Alston
    Alston over 9 years
    For this instruction: byte[] fileData = new byte[file.length()];, if the file size is too large, memory leak would happened!
  • Justin Breitfeller
    Justin Breitfeller over 9 years
    It wouldn't be a memory leak, but it could be an out of memory error if the allocation is too large. In this question, he was doing a 2 mb allocation which will probably succeed on most devices (depending on the other memory requirements in his app).
  • Prashant
    Prashant almost 9 years
    byte[] fileData = new byte[file.length()]; this is not a correct solution, if the file is very big then it'll give the same outOfMemoryError. I've already tried this. Please provide a solution which is perfectly working.