Napisałem klasę parsera dla konkretnego formatu binarnego (nfdump, jeśli ktokolwiek jest zainteresowany), który używa MappedByteBuffer java.nio do czytania plików o wielkości kilku GB. Format binarny to po prostu seria nagłówków, a przede wszystkim stałe rekordy binarne, które są wysyłane do wywoływanego przez wywołanie nextRecord(), która przesuwa maszynę stanu, zwracając wartość null, gdy jest ona zakończona. Działa dobrze. Działa na maszynie programistycznej.Problem mapy Java/Nio/NFS powodujący błąd maszyny wirtualnej: "wystąpił błąd w niedawnej niebezpiecznej operacji dostępu do pamięci w skompilowanym kodzie Java"
Na moim hoście produkcyjnym może działać przez kilka minut lub godzin, ale zawsze wydaje się wyrzucać "java.lang.InternalError: wystąpiła usterka w ostatniej niełatwej operacji dostępu do pamięci w skompilowanym kodzie Java", dotykając jednego z metody Map.getInt, getShort, tzn. operacja odczytu na mapie. (?)
niekontrowersyjnego kod, który tworzy mapy to:
/** 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);
}
a potem użyć różnych map.get * Metody czytać szorty, ints, tęskni i inne sekwencje bajtów, przed trafienie na koniec pliku i zamknięcie mapy.
Nigdy nie widziałem wyjątku rzucanego na mojego hosta rozwoju. Ale istotną różnicą między moim hostem produkcyjnym a rozwojem jest to, że czytam sekwencje tych plików przez NFS (prawdopodobnie 6-8 TB w końcu, wciąż rośnie). Na mojej maszynie deweloperskiej mam mniejszy wybór tych plików lokalnie (60 GB), ale kiedy eksploduje na hoście produkcyjnym, to zwykle na długo przed osiągnięciem 60 GB danych.
Oba urządzenia obsługują Javę 1.6.0_20-b02, chociaż hostem produkcyjnym jest Debian/Lenny, hostem dev jest Ubuntu/karmic. Nie jestem przekonany, że to coś zmieni. Oba urządzenia mają 16 GB pamięci RAM i działają z tymi samymi ustawieniami sterty java.
Uważam, że jeśli istnieje błąd w moim kodzie, jest wystarczająco dużo błędu w JVM, aby nie wyrzucić mi właściwego wyjątku! Ale myślę, że jest to po prostu szczególny błąd implementacji JVM z powodu interakcji między NFS a mmap, prawdopodobnie powtórzenie się 6244515, które jest oficjalnie naprawione.
Próbowałem już dodać wywołanie "load", aby zmusić MappedByteBuffer do załadowania jego zawartości do pamięci RAM - wydawało się, że opóźniłem ten błąd podczas jednego z przeprowadzonych testów, ale nie mogłem temu zapobiec. A może to był zbieg okoliczności, który był najdłuższy, jaki zdarzył się przed awarią!
Jeśli czytałeś tak daleko i robiłeś już takie rzeczy z java.nio wcześniej, jaki byłby twój instynkt? Teraz moje jest przepisanie go bez nio :)
Zgaduję, że już widziałeś D8 (http://nfs.sourceforge.net/) – Justin
Nie, dzięki, ale też nie piszę do tych plików. –
Widzę to z plikami mapowanymi w pamięci w lokalnych systemach plików ext4 i tmpfs z Javą 7u1. –