Java JVM被MappedByteBuffer杀死

Java JVM被MappedByteBuffer杀死,java,jvm,Java,Jvm,我有这个功能: private double[] readTableDouble(final RandomAccessFile file, final long startIndex, final int length) throws IOException { double[] doubles; try (FileChannel channel = file.getChannel()) { MappedByteBuffer buffer = channe

我有这个功能:

    private double[] readTableDouble(final RandomAccessFile file, final long startIndex, final int length) throws IOException {
    double[] doubles;
    try (FileChannel channel = file.getChannel()) {
        MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, startIndex * 8, length * 8);
        int byteIndex = buffer.limit() - 8;
        doubles = new double[length];
        int doubleIndex = 0;
        while (byteIndex > 0 && doubleIndex < length) {
            long l = 0;
            for (int i = 0; i < 8; i++) {
                l |= ((long) (buffer.get(byteIndex + i) & 0xFF)) << i * 8;
            }
            byteIndex -= 8;
            if (l != fillerLong) {
                doubles[doubleIndex++] = Double.longBitsToDouble(l);
            }
        }
        if (doubleIndex == length) {
            file.close();
            channel.close();
            return doubles;
        }

        // try again from the start if not enough numbers
        buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, (startIndex + length) * 8);
        byteIndex = buffer.limit() - 8;
        doubleIndex = 0;
        while (byteIndex > 0 && doubleIndex < length) {
            long l = 0;
            for (int i = 0; i < 8; i++) {
                l |= ((long) (buffer.get(byteIndex + i) & 0xFF)) << i * 8;
            }
            byteIndex -= 8;
            if (l != fillerLong) {
                doubles[doubleIndex++] = Double.longBitsToDouble(l);
            }
        }
    }
    file.close();
    return doubles;
}
此函数被调用数十万次,但是返回的缓冲区会很快被释放。没有多线程,文件大小约为340kB


你知道为什么吗?探查器与JVM一起被杀死。

没有明确定义的时间可以释放MappedByteBuffer分配的VM,因此它永远不会被释放。因此,在Java中打开大量内存映射文件是非常困难的。

我想几乎不可能说出原因,但是hs_err_pid8817.log可能包含一些有趣的信息。您可能希望添加此文件堆栈跟踪的相关部分,等等,也许有人可以解释它们。最可能的原因是您的映射总数已超过某些操作系统限制,您正在以只读方式映射,因此它应该只是虚拟空间,而不是实际的提交费用。我写这篇文章并不是为了回答这个问题,因为在这种情况下你没有理由使用映射缓冲区。那么,请告诉我,为什么你要移位来创建一个double,而你只需要调用getDouble?或者更好,把你的字节缓冲区变成双缓冲区?@kdgregory:我必须使用映射,因为这是最快的方法。我必须用手移动位,因为我不想依赖endiannes。另外,我需要检查数字==填充。Re:映射总数:我一次只处理一个文件。如何告诉JVM取消映射缓冲区?我认为内存映射的性能要比你想象的低得多,但我不会浪费我或你的时间来说服你。如果你想破解清理缓冲区的方法,请查看src.jar或grepcode中的DirectByteBuffer代码。实际上,直接缓冲区是由幻象引用管理的,因此当GC确定没有引用时,将取消映射。还有一些黑客可以处理这样一个事实:您可能正在分配大量堆外内存和少量堆内内存,这样GC就不会正常运行。@kdgregory这一定是新的。甲骨文公司有一个bug报告,几乎完全符合我在这里所说的。至少从1.6开始,我非常肯定从1.5开始。如果你去GrepCode,你可以在Unsafe中找到max buffers hack,在DirectByteBuffer中找到cleaner。
Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x000000077f280000, 13107200, 0) failed; error='Cannot allocate memory' (errno=12)
There is insufficient memory for the Java Runtime Environment to continue.
Native memory allocation (malloc) failed to allocate 13107200 bytes for committing reserved memory.
An error report file with more information is saved as:
/home/lukasz/Documents/NetBeansProjects/PPP/hs_err_pid8817.log
Java Result: 1