I have created the following demo to see the MMF begaviour (I want to use it as a very large array of long values).
import java.nio._, java.io._, java.nio.channels.FileChannel
object Index extends App {
val formatter = java.text.NumberFormat.getIntegerInstance
def format(l: Number) = formatter.format(l)
val raf = new RandomAccessFile("""C:\Users\...\Temp\96837624\mmf""", "rw")
raf.setLength(20)
def newBuf(capacity: Int) = {
var bytes= 8.toLong*capacity
println("new buf " + format(capacity) + " words = " + format(bytes) + " bytes")
// java.io.IOException: "Map failed" at the following line
raf.getChannel.map(FileChannel.MapMode.READ_WRITE, 0, bytes).asLongBuffer()
}
(1 to 100 * 1000 * 1000).foldLeft(newBuf(2): LongBuffer){ case(buf, i) =>
if (Math.random < 0.000009) println(format(buf.get(buf.position()/2)))
(if (buf.position == buf.capacity) {
val p = buf.position
val b = newBuf(buf.capacity * 2)
b.position(p) ; b
} else buf).put(i)
}
raf.close
It fails with the output
16,692,145
16,741,940
new buf 67,108,864
[error] (run-main-1) java.io.IOException: Map failed
java.io.IOException: Map failed
at sun.nio.ch.FileChannelImpl.map(FileChannelImpl.java:907)
I see a 512-MB file created and system seems failed to expand it to 1 GB.
If, however, instead of initial size of 2 long words, foldLeft(newBuf(2))
, I use 64M long words, newBuf(64*1024*1027)
, runtime succeeds creating 1GB file and fails when it tries to create 2GB file with
new buf 268 435 458 words = 2 147 483 664 bytes
java.lang.IllegalArgumentException: Size exceeds Integer.MAX_VALUE
at sun.nio.ch.FileChannelImpl.map(Unknown Source)
I ran it with 64-bit jvm.
I am also not sure how to close the buffer to release it for later application in sbt and be sure that data will ultimately appear in the file. The mechanism looks utterly unreliable.
Ok, one day of experiments has demonstrated that 32-bit JVM fails with
IOException: Map failed
at 1 GB no matter what. In order to circumvent theSize exceeds Integer.MAX_VALUE
with mapping at 64-bit machines, one should should use multiple buffers of affordable size, e.g. 100 mb each is fine. That is because buffers are addressed by integer.What regards this question, you can keep all such buffers open in memory simultaneously, i.e. there is no need to close one buffer => null before you allocate the next effectively increment the file size, as the following demo demonstrates
at least in Windows. Using this program, I have managed to create mmf file larger than my machine memory (not to speak about JVM's -Xmx, which play no role at all in these matters). Just slow down the file generation selecting some text in the Windows console with mouse (program will pause until you release the selection) because otherwise Windows will evict all other performance critical staff to page file and your PC will die in thrashing.
BTW, PC dies in thrashing despite I write only into the end of file and Windows could evict my unused gigabyte blocks. Also, I have noticed that the block I am writing is actually read
The following output
is accompanied by following system requests
but that is another story.
It turns out that this answer is duplicate of Peter Lawrey's except that mine question is dedicated to 'Map failed' and 'Integer range exceeded' when mapping large buffers whereas original question is concerned with OutOfMem in JVM, which has nothing to do with I/O.