ali molaie
ali molaie

Reputation: 21

how to fix OutOfMemoryError android studio

i have a application for extract 7zip file i use this two lib for extract

compile 'org.apache.commons:commons-compress:1.12'

compile files('libs/xz-1.3.jar')

and this is my code

      public void unzip() {
    try  {
        File fc = new File(_location,"Driver2.7z");
        System.out.println("file size"+fc.length());
        //File fd = new File(_location,"Driver2.bin");
        SevenZFile sevenZFile = new SevenZFile(fc);
        SevenZArchiveEntry entry = sevenZFile.getNextEntry();
        System.out.println( "Unzipping " );
        while(entry!=null){
            System.out.println(entry.getName());
            FileOutputStream out = new FileOutputStream(_location + entry.getName());
            //FileOutputStream out = new FileOutputStream(entry.getName());
            System.out.println(entry.getName());
            byte[] content = new byte[(int) entry.getSize()];
            System.out.println(entry.getName());
            sevenZFile.read(content, 0, content.length);
            System.out.println(entry.getName());
            out.write(content);
            System.out.println(entry.getName());
            out.close();
            entry = sevenZFile.getNextEntry();
            System.out.println(entry.getName());
        }
        sevenZFile.close();
   
        Log.d("Unzip", "Unzipping complete. path :  " +_location );
    } catch(Exception e) {
        System.out.println("Decompress"+ "unzip"+ e.getMessage());
    }

}

with this code i get this error on some device

 E/AndroidRuntime: FATAL EXCEPTION: Thread-218
                                                              Process: ir.milano.driver, PID: 30164
                                                              java.lang.OutOfMemoryError: Failed to allocate a 137881308 byte allocation with 4194304 free bytes and 129MB until OOM
                                                                  at com.darkgamers.pepsiman.browser.mainmenu.DecompressFast.unzip(DecompressFast.java:38)
                                                                  at ir.milano.driver.CopyFiles$1.run(CopyFiles.java:75)

the problem is this line

byte[] content = new byte[(int) entry.getSize()];

Upvotes: 0

Views: 858

Answers (2)

weston
weston

Reputation: 54811

You're trying to extract a large file from the zip, ~130MB. You shouldn't do this by allocating one large contiguous block of bytes. Instead, you should work with Streams.

Streams don't open the whole content at once, rather just keep track of a position into the file allowing reading just part of the file at a time. You already have an output stream FileOutputStream you just need to find the relevant API call to get an input stream and research copying from an input stream to an output.

Alternatively, if no Stream API is provided, you can read and write in multiple chunks using sevenZFile.read but with a much smaller buffer.

byte[] content = new byte[16 * 1024]; //fixed reasonable size buffer
while((int noBytesRead = sevenZFile.read(content, 0, content.size()) != -1){
   //write the noBytesRead from content into your stream.
}

Upvotes: 3

Andreas
Andreas

Reputation: 159175

Don't load the entire Zip entry content into memory. Copy the content in blocks. Buffer size of 4K has been shown to be efficient in tests.

Also, use try-with-resources and enhanced for loop.

byte[] buffer = new byte[4096];
try (SevenZFile sevenZFile = new SevenZFile(fc)) {
    for (SevenZArchiveEntry entry : sevenZFile.getEntries()) {
        try (FileOutputStream out = new FileOutputStream(_location + entry.getName())) {
            for (int len; (len = sevenZFile.read(buffer)) > 0; ) {
                out.write(buffer, 0, len);
            }
        }
    }
}

Upvotes: 1

Related Questions