Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 6478546
Votes 12
Synopsis FileInputStream.read() throws OutOfMemoryError when there is plenty available
Category java:classes_io
Reported Against
Release Fixed
State 5-Cause Known, bug
Priority: 4-Low
Related Bugs
Submit Date 05-OCT-2006
Description
FULL PRODUCT VERSION :
java version "1.5.0_06"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)
Java HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode)

java version "1.5.0_08"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_08-b03)
Java HotSpot(TM) Client VM (build 1.5.0_08-b03, mixed mode, sharing)

java version "1.6.0-beta2"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.6.0-beta2-b72)
Java HotSpot(TM) Client VM (build 1.6.0-beta2-b72, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Windows XP SP2

EXTRA RELEVANT SYSTEM CONFIGURATION :
2GB RAM

A DESCRIPTION OF THE PROBLEM :
Attempting to read a large file in one chunck with FileInputStream.read() with TOO large heap space causes OutOfMemory exception. According to spec, AFIK, even if the read() runs out of space it should just return with as much data as it can, not throw an exception. And in any case there was plenty of memory available, and further more with smaller heap the code runs ok!

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached code with heap space (-Xmx) 1300M and 1400M. With 1300M it runs ok, with 1400M it throws an exception. The "bigfile" in my test case had a length of 251 503 002 bytes. I can provide the file, but it should not make difference as the programs just tries to read all the bytes.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Either the FileInputStream.read() should have read the whole file (as there was 1400 MB of memory available and the file size was 'only' 250MB) or it should have read some smaller part of the file and returned the number of bytes read. It should not have thrown an exception.
ACTUAL -
With TOO large heap size the code throws OutOfMemory exception.

ERROR MESSAGES/STACK TRACES THAT OCCUR :

C:\tests>"C:\Program Files\Java\jre1.6.0\bin\java.exe" -Xmx1400m -classpath . r3
d
size: 251503002
buf ok
Exception in thread "main" java.lang.OutOfMemoryError
        at java.io.FileInputStream.readBytes(Native Method)
        at java.io.FileInputStream.read(Unknown Source)
        at r3d.main(r3d.java:19)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.awt.*;
import java.io.*;

public class r3d {

    public static void main(String[] args) {
	try {
		int size = 501*501*501*2;

		FileInputStream fis = new FileInputStream("bigfile"); // Any file with size >= 501*501*501*2

		System.out.println("size: " + size);

		byte buf[] = new byte[size];

		System.out.println("buf ok");


		int bytesRead = fis.read(buf, 0,size);
		System.out.println("Bytes read " + bytesRead);
	}
	catch (Exception e) {
		e.printStackTrace();
		System.out.println(e);
		System.out.println();
	}
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Attempting to read the file in multiple smaller chunks seem to work,.
Posted Date : 2006-10-05 09:11:13.0
Work Around
N/A
Evaluation
A malloc'ed buffer is used for I/O when byte array is larger than 8k. We should consider limiting the size to something reasonable (say 1MB). Additioning, this temporary buffer could be a thread local rather than malloc'ed buffer to reduce the cost of malloc/free per I/O.
Posted Date : 2009-08-17 12:35:10.0
Comments
  
  Include a link with my name & email   

Submitted On 06-DEC-2006
sebastiano.vigna
Same problem on Linux with 

java version "1.5.0_09"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_09-b01)
Java HotSpot(TM) Server VM (build 1.5.0_09-b01, mixed mode)

We used from -Xmx2000 to -Xmx2600M, but a read() into a 1.1GB array was always giving out-of-memory errors. Breaking the read() in 128KiB did work.


Submitted On 26-DEC-2006
hlavac
Happens to me too on Windows XP x64 with 32bit JVM.

Some more observations:
- Only happens on 32bit JVM with very large amounts of memory
- Problem happens in native method
- Both FileInputStream.read(byte[],int,int) and RandomAccessFile.read(byte[],int,int) are affected (same implementation?)
- The more memory you give to JVM, the smaller piece of data you can read on single read() without getting a mysterious OutOfMemoryError.

I have tested that on my system, with both JDK 1.5 and 1.6:
- with  -Xms824m -Xmx824m  you can still read up to 797,467,108 bytes long array in one read() call, which is the largest byte[] array you could get
- with -Xms825m -Xmx825m  read of 799433188 bytes array throws OutOfMemoryError even though machine has 3GB physical RAM
- I was unable to set memory on Windows to more than -Xms1594m -Xmx1594m having 3GB of physical memory, anything more fails to start the JVM (2GB limitation?), and with this much memory you can read max 143,982,560 bytes without getting OutOfMemoryError.

Looks to me more like address space exhaustion than memory exhaustion???

Anyway it sucks when you want to process very large data.


Submitted On 26-DEC-2006
hlavac
Here, test case to play with:
[code]
package largefilereadbug;

import java.io.*;

public class Main {

    public static final void main(String[] args) throws Throwable {
        
        File f = File.createTempFile("biggie",".big").getCanonicalFile();
        f.deleteOnExit();
        RandomAccessFile raf = new RandomAccessFile(f,"rw");
        try {
            System.out.println("JVM: "+System.getProperty("java.vm.version"));
            System.out.println("Max mem: "+Runtime.getRuntime().maxMemory());
            System.out.println("Current mem: "+Runtime.getRuntime().totalMemory());
            
            System.out.println("Finding size of largest allocatable array...");
            int biggie = findMaximumByteArraySize();
            System.out.println("Maximum allocatable: byte["+biggie+"]");
            raf.setLength(biggie);
            
            try {
                byte[] data = new byte[biggie];

                System.out.println("Got array, trying to read into it");

                try {
                    raf.read(data);
                } catch (OutOfMemoryError x) {
                    System.out.println("WTF!? got OutOfMemoryError from within read()!");
                    throw x;
                }
            
                System.out.println("SUCCESS!!! Everything works as it should.");
            
            } catch (OutOfMemoryError e) {
                System.out.println("This didnt work ;(");
                throw e;
            }
            
            
        } finally {
            raf.close();
            f.delete();
        }
    }
    
    static final int findMaximumByteArraySize() {
        if (allocates(0x7fffffff)) return 0x7fffffff;
        int max = 0x7fffffff;   // upper bound
        int min = 0;            // lower bound
        while (min<max) {
            int half = (max-min)/2+min;
            if (allocates(half)) {
                // yes, go up with the lower bound
                min = half+1;
            } else {
                // no, go down with upper bound
                max = half-1;
            }
        }
        return min;
    }
        
    static final boolean allocates(int size) {
        byte[] test = null;
        try {
            test = new byte[size];
            test = null;
            System.gc();
            return true;
        } catch (OutOfMemoryError e) {
        }
        return false;
    }
}
[/code]


Submitted On 13-MAR-2009
MichaelMcCandless
This is a nasty bug!  It's affecting users of Lucene:

  http://lucene.markmail.org/message/zpz6n5z3dx3gm2xi

Is it known whether this also affects 64 bit JREs?


Submitted On 21-MAR-2009
SanneGrinovero
Using Java HotSpot(TM) 64-Bit Server VM (build 14.0-b11, mixed mode)
on 64 bit linux (fedora 10) I don't have problems;
I've succesfully run the testcase submitted by hlavac with several configurations from 32m to 3GB.
So I think linux 64bit is not affected?



PLEASE NOTE: JDK6 is formerly known as Project Mustang