Fix for OutOfMemory exception when writing large files

222 views
Skip to first unread message

Mark

unread,
Aug 11, 2012, 5:09:56 PM8/11/12
to mp4parser-...@googlegroups.com
First off thanks for providing this library.  While using it, I was having some problems writing out large (>1GB) files:

Exception in thread "main" java.io.IOException: Map failed
    at sun.nio.ch.FileChannelImpl.map(Unknown Source)
    at sun.nio.ch.FileChannelImpl.transferToTrustedChannel(Unknown Source)
    at sun.nio.ch.FileChannelImpl.transferTo(Unknown Source)
    at com.coremedia.iso.boxes.mdat.MediaDataBox.getBox(MediaDataBox.java:88)
    at com.coremedia.iso.IsoFile.getBox(IsoFile.java:177)
    at mmm.mp4.Mp4File.save(Mp4File.java:237)
    at mmm.mp4.Mp4File.main(Mp4File.java:252)
Caused by: java.lang.OutOfMemoryError: Map failed
    at sun.nio.ch.FileChannelImpl.map0(Native Method)
    ... 7 more

There seems to be a fair amount of documentation describing that FileChannel.transferTo has some problems on Windows for large files.  Using the technique described at http://dzone.com/snippets/java-filecopy-using-nio, I modified MediaDataBox as such:

    private static void transfer (FileChannel from, long position, long count, WritableByteChannel to) throws IOException {
        long maxCount = (64 * 1024 * 1024) - (32 * 1024);
        long offset = 0;
        while (offset < count) {
            offset += from.transferTo(position + offset, Math.min(maxCount, count - offset), to);
        }
    }

    public void getBox(WritableByteChannel writableByteChannel) throws IOException {
        if (fileChannel != null) {
            assert checkStillOk();
            transfer(fileChannel, startPosition - header.limit(), contentSize + header.limit(), writableByteChannel);
        } else {
            header.rewind();
            writableByteChannel.write(header);
            writableByteChannel.write(content);
        }
    }

This seems to have fixed the issue for me.  Please feel free to use this change or make modifications to it in your code stream if you would like.

Cheers.
-Mark

Sebastian Annies

unread,
Aug 12, 2012, 5:27:05 AM8/12/12
to mp4parser-...@googlegroups.com
Hi Mark,

generally I don't like magic numbers (as the 64MB - 32KB) as they are most likely very platform and jdk dependent but if it solves your issue I'm fine with it - the size of number seems reasonable.
A bit more explanation if anyone is interested: The transfer operation on Windows obviously first maps the region that will be transferred into the memory and then transfers it. That mapping operation uses up virtual memory (no actual physical memory) and on 32 bit systems you don't have  large address space - it's limited to 2GB and it seems that the JVM could not acquire enough free addresses in your case.

Patch is applied with r742. Thank you!

Best Regards,
Sebastian

2012/8/11 Mark <zenith....@gmail.com>
Reply all
Reply to author
Forward
0 new messages