He escrito una clase analizadora para un formato binario particular (nfdump si alguien está interesado) que utiliza MappedByteBuffer de java.nio para leer archivos de unos pocos GB cada uno. El formato binario es simplemente una serie de encabezados y, en su mayoría, registros binarios de tamaño fijo, que se envían a la llamada llamando a nextRecord(), que empuja a la máquina de estado y devuelve nulo cuando termina. Funciona bien. Funciona en una máquina de desarrollo.Problema Java map/nio/NFS que causa un error VM: "se produjo un error en una operación reciente de acceso a memoria inseguro en código Java compilado"
En mi host de producción, puede ejecutarse durante unos minutos u horas, pero siempre parece lanzar "java.lang.InternalError: se produjo un error en una operación reciente de acceso a memoria inseguro en el código compilado de Java", digitación uno de los métodos Map.getInt, getShort, es decir, una operación de lectura en el mapa. (?)
El controvertido código que configura el mapa es la siguiente:
/** 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);
}
y luego utilizar los distintos métodos map.get * para leer pantalones cortos, largos y enteros, otras secuencias de bytes, antes golpeando el final del archivo y cerrando el mapa.
Nunca he visto la excepción lanzada en mi host de desarrollo. Pero el punto significativo de diferencia entre mi host de producción y el desarrollo es que en el primero, estoy leyendo secuencias de estos archivos a través de NFS (probablemente 6-8TB eventualmente, aún creciendo). En mi máquina de desarrollo, tengo una selección más pequeña de estos archivos localmente (60GB), pero cuando explota en el host de producción, generalmente es mucho antes de que llegue a los 60GB de datos.
Ambas máquinas ejecutan java 1.6.0_20-b02, aunque el host de producción ejecuta Debian/lenny, el host dev es Ubuntu/karmic. No estoy convencido de que eso haga la diferencia. Ambas máquinas tienen 16 GB de RAM y funcionan con la misma configuración de almacenamiento en java.
Considero que si hay un error en mi código, ¡hay suficiente error en la JVM para no arrojarme una excepción! Pero creo que es solo un error de implementación de JVM en particular debido a las interacciones entre NFS y mmap, posiblemente una recurrencia de 6244515 que se ha corregido oficialmente.
Ya intenté agregar una llamada de "carga" para forzar a MappedByteBuffer a cargar sus contenidos en la RAM, esto pareció retrasar el error en la única ejecución de prueba que hice, pero no la evité. ¡O podría ser una coincidencia que fue el tiempo más largo que había pasado antes de estrellarse!
Si ha leído hasta aquí y ha hecho este tipo de cosas con java.nio antes, ¿cuál sería su instinto? En este momento el mío es reescribirlo sin nio :)
Supongo que ya has visto D8 de (http://nfs.sourceforge.net/) – Justin
No tuve, gracias, pero tampoco estoy escribiendo en estos archivos. –
Estoy viendo esto ocurrir con los archivos mapeados de memoria en los sistemas locales de archivos ext4 y tmpfs con Java 7u1. –