2015-12-04 4 views
0

Я создал следующее демо, чтобы увидеть MMF begaviour (я хочу использовать его как очень большой массив длинных значений).Инкрементальное выделение буфера с памятью и ошибка при размере 1 ГБ

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 

Это терпит неудачу с выходом

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) 

Я вижу 512-MB-файл, созданный и системы, кажется, не в состоянии расширить его до 1 Гб.

Если, однако, вместо первоначального размера 2 длинных слов, foldLeft(newBuf(2)), я использую 64M длинные слова, newBuf(64*1024*1027), во время выполнения удается создать 1 Гб файл и терпит неудачу, когда он пытается создать 2 Гб файл с

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 запускал его с 64-битным jvm.

Я также не уверен, как закрыть буфер, чтобы освободить его для последующего приложения в sbt и убедиться, что в конечном итоге данные будут отображаться в файле. Механизм выглядит совершенно ненадежным.

+0

В чем вопрос? – the8472

ответ

0

Хорошо, один день экспериментов показал, что 32-разрядная JVM не работает с IOException: Map failed на 1 ГБ независимо от того, что. Чтобы обойти Size exceeds Integer.MAX_VALUE с отображением на 64-битных машинах, следует использовать несколько буферов доступного размера, например. 100 мб каждый в порядке. Это потому, что buffers are addressed by integer.

Что касается этого вопроса, вы можете сохранить все такие буферы открыты в памяти одновременно, т.е. нет необходимости закрывать один буфер => NULL, прежде чем выделить следующий эффективно увеличивать размер файла, как показано в следующем демо демонстрирует

import Utils._, java.nio._, java.io._, java.nio.channels.FileChannel 

object MmfDemo extends App { 

    val bufAddrWidth = 25 /*in bits*/ // Every element of the buff addresses a long 
    val BUF_SIZE_WORDS = 1 << bufAddrWidth ; val BUF_SIZE_BYTES = BUF_SIZE_WORDS << 3 
    val bufBitMask = BUF_SIZE_WORDS - 1 
    var buffers = Vector[LongBuffer]() 
    var capacity = 0 ; var pos = 0 
    def select(pos: Int) = { 
     val bufn = pos >> bufAddrWidth // higher bits of address denote the buffer number 
     //println(s"accessing $pos = " + (pos - buf * wordsPerBuf) + " in " + buf) 
     while (buffers.length <= bufn) expand 
     pass(buffers(bufn)){_.position(pos & bufBitMask)} 
    } 
    def get(address: Int = pos) = { 
     pos = address +1 
     select(address).get 
    } 
    def put(value: Long) { 
     //println("writing " + value + " to " + pos) 
     select(pos).put(value) ; pos += 1 
    } 
    def expand = { 
     val fromByte = buffers.length.toLong * BUF_SIZE_BYTES 
     println("adding " + buffers.length + "th buffer, total size expected " + format(fromByte + BUF_SIZE_BYTES) + " bytes") 

     // 32bit JVM: java.io.IOException: "Map failed" at the following line if buf size requested is larger than 512 mb 
     // 64bit JVM: IllegalArgumentException: Size exceeds Integer.MAX_VALUE 
     buffers :+= fc.map(FileChannel.MapMode.READ_WRITE, fromByte, BUF_SIZE_BYTES).asLongBuffer() 
     capacity += BUF_SIZE_WORDS 
    } 

    def rdAll(get: Int => Long) { 
     var firstMismatch = -1 
     val failures = (0 until parse(args(1))).foldLeft(0) { case(failures, i) => 
      val got = get(i) 
      if (got != i && firstMismatch == -1) {firstMismatch = i; println("first mismatch at " +format(i) + ", value = " + format(got))} 
      failures + ?(got != i, 1, 0) 
     } ; println(format(failures) + " mismatches") 
    } 

    val raf = new RandomAccessFile("""C:\Temp\mmf""", "rw") 
    val fc = raf.getChannel 
    try { 

     if (args.length < 1) { 
      println ("usage1: buf_gen <len in long words>") 
      println ("usage1: raf_gen <len in long words>") 
      println("example: buf_gen 30m") 
      println("usage2: raf_rd <size in words>") 
      println("usage3: buf_rd <size in words>") 
     } else { 
      val t1 = System.currentTimeMillis 
      args(0) match { 
       case "buf_gen" => raf.setLength(0) 
        (0 until parse(args(1))) foreach {i => put(i.toLong)} 
       case "raf_gen" => raf.setLength(0) 
        (0 until parse(args(1))) foreach {i =>raf.writeLong(i.toLong)} 
         //fc.force(true) 
       case "rd_raf" => rdAll{i => raf.seek(i.toLong * 8) ; raf.readLong()} 
       case "rd_buf" => rdAll(get) 
       case u =>println("unknown command " + u) 
      } ; println("finished in " + (System.currentTimeMillis - t1) + " ms") 
     } 
    } finally { 
     raf.close ; fc.close 

     buffers = null ; System.gc /*GC needs to close the buffer*/} 

} 

object Utils { 
    val formatter = java.text.NumberFormat.getIntegerInstance 
    def format(l: Number) = formatter.format(l) 

    def ?[T](sel: Boolean, a: => T, b: => T) = if (sel) a else b 
    def parse(s: String) = { 
     val lc = s.toLowerCase() 
     lc.filter(_.isDigit).toInt * 
      ?(lc.contains("k"), 1000, 1) * 
      ?(lc.contains("m"), 1000*1000, 1) 
    } 
    def eqa[T](a: T, b: T) = assert(a == b, s"$a != $b") 
    def pass[T](a: T)(code: T => Unit) = {code(a) ; a} 
} 

хотя бы в Windows. Используя эту программу, мне удалось создать файл mmf, превышающий мою память (не говоря о JVM -Xmx, которые вообще не играют никакой роли в этих вопросах). Просто замедлите создание файла, выделив какой-то текст в консоли Windows с помощью мыши (программа остановится до тех пор, пока вы не отпустите выбор), потому что в противном случае Windows выведет всех других сотрудников, имеющих критическую критичность, в файл страницы, и ваш компьютер умрет от взлома.

BTW, компьютер умирает, несмотря на то, что я пишу только в конец файла, и Windows может вывести мои неиспользуемые блоки гигабайта. Кроме того, я заметил, что блок я пишу это на самом деле читать

Следующий выход

adding 38th buffer, total size expected 12,480,000,000 bytes 
adding 39th buffer, total size expected 12,800,000,000 bytes 

сопровождается следующей системой просит

5:24,java,"QueryStandardInformationFile",mmf,"SUCCESS","AllocationSize: 12 480 000 000, EndOfFile: 12 480 000 000, NumberOfLinks: 1, DeletePending: False, Directory: False" 
5:24,java,"SetEndOfFileInformationFile",mmf,"SUCCESS","EndOfFile: 12 800 000 000" 
5:24,java,"SetAllocationInformationFile",mmf,"SUCCESS","AllocationSize: 12 800 000 000" 
5:24,java,"CreateFileMapping",mmf,"FILE LOCKED WITH WRITERS","SyncType: SyncTypeCreateSection, PageProtection: " 
5:24,java,"QueryStandardInformationFile",mmf,"SUCCESS","AllocationSize: 12 800 000 000, EndOfFile: 12 800 000 000, NumberOfLinks: 1, DeletePending: False, Directory: False" 
5:24,java,"CreateFileMapping",mmf,"SUCCESS","SyncType: SyncTypeOther" 
5:24,java,"ReadFile",mmf,"SUCCESS","Offset: 12 480 000 000, Length: 32 768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal" 
5:24,java,"ReadFile",mmf,"SUCCESS","Offset: 12 480 032 768, Length: 32 768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal" 
5:24,java,"ReadFile",mmf,"SUCCESS","Offset: 12 480 065 536, Length: 32 768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal" 
5:24,java,"ReadFile",mmf,"SUCCESS","Offset: 12 480 098 304, Length: 32 768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal" 
5:24,java,"ReadFile",mmf,"SUCCESS","Offset: 12 480 131 072, Length: 20 480, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal" 

skipped 9000 reads 

5:25,java,"ReadFile",mmf,"SUCCESS","Offset: 12 799 836 160, Length: 32 768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal" 
5:25,java,"ReadFile",mmf,"SUCCESS","Offset: 12 799 868 928, Length: 32 768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal" 
5:25,java,"ReadFile",mmf,"SUCCESS","Offset: 12 799 901 696, Length: 32 768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal" 
5:25,java,"ReadFile",mmf,"SUCCESS","Offset: 12 799 934 464, Length: 32 768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal" 
5:25,java,"ReadFile",mmf,"SUCCESS","Offset: 12 799 967 232, Length: 32 768, I/O Flags: Non-cached, Paging I/O, Synchronous Paging I/O, Priority: Normal" 

, но это другая история.

Оказывается, этот ответ дублируется Peter Lawrey's, за исключением того, что мой вопрос посвящен «Ошибка карты» и «Целочисленный диапазон превышен» при сопоставлении больших буферов, тогда как исходный вопрос касается OutOfMem в JVM, что не имеет ничего общего с вводом/выводом.

 Смежные вопросы

  • Нет связанных вопросов^_^