如何正确关闭MappedByteBuffer?

问题描述 投票:7回答:3

这是我正在运行的代码:

import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class Main {
    public static void main(String[] args) throws Exception {
        String filePath = "D:/temp/file";
        RandomAccessFile file = new RandomAccessFile(filePath, "rw");

        try {
            MappedByteBuffer buffer = file.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 128);

            // Do something
            buffer.putInt(4);
        } finally {
            file.close();
            System.out.println("File closed");
        }

        System.out.println("Press any key...");
        System.in.read();

        System.out.println("Finished");
    }
}

在按下键之前,我试图在FAR Manager中手动删除文件。但是FAR表示文件已锁定:

 The process cannot access the file because it is being used by another process.
                     Cannot delete the file
                         D:\temp\file
                    Object is being opened in:
 Java(TM) Platform SE binary (PID: 5768, C:\Program Files\Java\jdk1.8.0_05\bin\javaw.exe)

仅在按下一个键后,应用程序终止,我可以删除该文件。

我的代码有什么问题?

java java-9 randomaccessfile mappedbytebuffer
3个回答
7
投票

尝试这个。

public class Test
{
    public static void main(String[] args) throws Exception {
        String filePath = "D:/temp/file";
        RandomAccessFile file = new RandomAccessFile(filePath, "rw");
        FileChannel chan = file.getChannel();
        try {
            MappedByteBuffer buffer = chan.map(FileChannel.MapMode.READ_WRITE, 0, 128);

            // Do something
            buffer.putInt(4);
            buffer.force();
            Cleaner cleaner = ((sun.nio.ch.DirectBuffer) buffer).cleaner();
            if (cleaner != null) {
                cleaner.clean();
            }
        } finally {
            chan.close();
            file.close();
            System.out.println("File closed");
        }

        System.out.println("Press any key...");
        System.in.read();

        System.out.println("Finished");
    }
}

2
投票

@@ SANN3的答案不再适用于Java 9。在Java 9中,可以使用新方法sun.misc.Unsafe.invokeCleaner。这是一个工作代码:

MappedByteBuffer buffer = ...

// Java 9+ only:
Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
Field unsafeField = unsafeClass.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Object unsafe = unsafeField.get(null);
Method invokeCleaner = unsafeClass.getMethod("invokeCleaner", ByteBuffer.class);
invokeCleaner.invoke(unsafe, buffer);

0
投票

尝试https://github.com/real-logic/agrona

其IOUtil类具有unmap(MappedByteBuffer)方法,该方法完全可以满足您的需求。它允许显式取消映射MappedByteBuffer。

但是,它在内部使用unmap(MappedByteBuffer),所以它可能不适用于所有JDK

© www.soinside.com 2019 - 2024. All rights reserved.