我已经编写了一个解析器类,用于解析特定的二进制格式(如果有人感兴趣,可以访问nfdump)。该解析器使用java.nio的MappedByteBuffer读取每个几GB的文件。该二进制格式只是一系列头和大部分固定大小的二进制记录,通过调用nextRecord()来提供给调用者,该方法会推动状态机,并在完成时返回null。它表现良好,在开发机上运行正常。
但是在生产主机上,它可能运行几分钟或几小时,但总是似乎会抛出“java.lang.InternalError:在编译的Java代码中发生最近的不安全内存访问操作错误”,指向Map.getInt、getShort方法之一,即映射中的读取操作。
设置地图的无争议(?)代码如下:
然后我使用各种map.get*方法读取shorts、ints、longs和其他字节序列,直到文件结尾并关闭该映射。在我的开发主机上从未看到过异常抛出。但我的生产主机和开发之间的重大差异是,在前者上,我通过NFS读取这些文件的序列(最终可能为6-8TB,仍在增长)。在我的开发机器上,我有一小部分这些文件的本地副本(60GB),但当它在生产主机上崩溃时,通常在达到60GB数据之前就已经崩溃了。两台机器都运行java 1.6.0_20-b02,虽然生产主机运行Debian / lenny,而开发主机运行Ubuntu / karmic。我不确定这是否会有任何区别。两台机器都有16GB RAM,并且使用相同的java堆设置运行。我认为如果我的代码有错误,JVM中肯定也有足够的错误没有抛出适当的异常!但我认为这只是一个特定的JVM实现bug,由于NFS和mmap之间的交互引起,可能是6244515的复发,这是正式修复的。
我已经尝试添加“load”调用来强制MappedByteBuffer加载其内容到RAM中-这似乎延迟了我进行的一个测试运行中的错误,但并没有防止它。或者这可能是巧合,那是它在崩溃之前持续的最长时间!
如果您已经读到这里并且曾经在java.nio中进行过此类操作,您的直觉会是什么?现在我的想法是重写它而不使用nio :)
但是在生产主机上,它可能运行几分钟或几小时,但总是似乎会抛出“java.lang.InternalError:在编译的Java代码中发生最近的不安全内存访问操作错误”,指向Map.getInt、getShort方法之一,即映射中的读取操作。
设置地图的无争议(?)代码如下:
/** 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);
}
然后我使用各种map.get*方法读取shorts、ints、longs和其他字节序列,直到文件结尾并关闭该映射。在我的开发主机上从未看到过异常抛出。但我的生产主机和开发之间的重大差异是,在前者上,我通过NFS读取这些文件的序列(最终可能为6-8TB,仍在增长)。在我的开发机器上,我有一小部分这些文件的本地副本(60GB),但当它在生产主机上崩溃时,通常在达到60GB数据之前就已经崩溃了。两台机器都运行java 1.6.0_20-b02,虽然生产主机运行Debian / lenny,而开发主机运行Ubuntu / karmic。我不确定这是否会有任何区别。两台机器都有16GB RAM,并且使用相同的java堆设置运行。我认为如果我的代码有错误,JVM中肯定也有足够的错误没有抛出适当的异常!但我认为这只是一个特定的JVM实现bug,由于NFS和mmap之间的交互引起,可能是6244515的复发,这是正式修复的。
我已经尝试添加“load”调用来强制MappedByteBuffer加载其内容到RAM中-这似乎延迟了我进行的一个测试运行中的错误,但并没有防止它。或者这可能是巧合,那是它在崩溃之前持续的最长时间!
如果您已经读到这里并且曾经在java.nio中进行过此类操作,您的直觉会是什么?现在我的想法是重写它而不使用nio :)