Ho scritto una classe parser per un particolare formato binario (nfdump se qualcuno è interessato) che usa java.nio's MappedByteBuffer per leggere i file di alcuni GB ciascuno. Il formato binario è solo una serie di intestazioni e soprattutto di record binari di dimensioni fisse, che vengono inviati al chiamante chiamando nextRecord(), che spinge sulla macchina di stato, restituendo null quando viene eseguito. Funziona bene. Funziona su una macchina di sviluppo.Problema di Java map/nio/NFS che causa un errore di VM: "un errore si è verificato in un'operazione di accesso alla memoria recente non sicura nel codice Java compilato"
Sul mio host di produzione, può essere eseguito per alcuni minuti o ore, ma sembra sempre lanciare "java.lang.InternalError: un errore si è verificato in un'operazione di accesso alla memoria recente non sicura in codice Java compilato", digitando uno di i metodi Map.getInt, getShort, ovvero un'operazione di lettura sulla mappa. (?)
Il incontrovertibile codice che imposta la mappa è questo:
/** Set up the map from the given filename and position */
protected void open() throws IOException {
// Set up buffer, is this all the flexibility we'll need?
channel = new FileInputStream(file).getChannel();
MappedByteBuffer map1 = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
map1.load(); // we want the whole thing, plus seems to reduce frequency of crashes?
map = map1;
// assumes the host writing the files is little-endian (x86), ought to be configurable
map.order(java.nio.ByteOrder.LITTLE_ENDIAN);
map.position(position);
}
e poi usare i vari map.get * metodi per leggere pantaloncini, int, long e altre sequenze di byte, prima di colpendo la fine del file e chiudendo la mappa.
Non ho mai visto l'eccezione generata sul mio host di sviluppo. Ma il punto significativo di differenza tra il mio host di produzione e lo sviluppo è che sul primo, sto leggendo sequenze di questi file su NFS (probabilmente 6-8 TB alla fine, ancora in crescita). Sulla mia macchina di sviluppo, ho una selezione più piccola di questi file a livello locale (60 GB), ma quando esplode nell'host di produzione è in genere ben prima che arrivi a 60 GB di dati.
Entrambe le macchine sono in esecuzione Java 1.6.0_20-b02, anche se l'host di produzione è in esecuzione Debian/Lenny, l'host dev è Ubuntu/karmico. Non sono convinto che farà alcuna differenza. Entrambe le macchine hanno 16 GB di RAM e sono in esecuzione con le stesse impostazioni di heap java.
ritengo che se c'è un bug nel mio codice, c'è abbastanza di un bug nella JVM non a me un'eccezione corretta! Ma penso che sia solo un particolare bug di implementazione di JVM a causa delle interazioni tra NFS e mmap, probabilmente una ricorrenza di 6244515 che è stata riparata ufficialmente.
Ho già provato ad aggiungere una chiamata "carica" per forzare il MappedByteBuffer a caricare il suo contenuto in RAM - questo sembrava ritardare l'errore nell'unica esecuzione di test che ho fatto, ma non impedirlo. Oppure potrebbe essere la coincidenza che è stata la più lunga che è durata prima di schiantarsi!
Se avete letto fino a questo punto e hanno fatto questo genere di cose con java.nio prima, quale sarebbe il tuo istinto essere? In questo momento la mia è di riscriverlo senza nio :)
io ti sto indovinando hai già visto D8 di (http://nfs.sourceforge.net/) – Justin
non avevo, grazie, ma poi non sto scrivendo a questi file uno. –
Sto vedendo questo si verificano con i file mappati in memoria su file system locali ext4 e tmpfs con Java 7u1. –