Java 调用MappedByteBuffer.force()的正当理由是什么?

Java 调用MappedByteBuffer.force()的正当理由是什么?,java,memory,io,real-time,nio,Java,Memory,Io,Real Time,Nio,我想有两个,但我想确认一下我在这里是否有意义: 1) JVM在一个未捕获的异常中退出=>这里可能是错误的,因为退出的JVM会以某种方式为我做这件事,但是为了安全起见,自己在关闭钩子中做这件事并没有什么坏处 2) 如果我必须“滚动”ByteBuffer,这意味着它将超过容量,我需要一个新的=>我正在考虑对已满的字节调用force(),然后丢弃它,然后从文件末尾开始创建一个新的字节 理想的解决方案是拥有一个永远不会超过容量的ByteBuffer,但我想检查一下这种情况并滚动字节缓冲区 那么您认为在上

我想有两个,但我想确认一下我在这里是否有意义:

1) JVM在一个未捕获的异常中退出=>这里可能是错误的,因为退出的JVM会以某种方式为我做这件事,但是为了安全起见,自己在关闭钩子中做这件事并没有什么坏处

2) 如果我必须“滚动”ByteBuffer,这意味着它将超过容量,我需要一个新的=>我正在考虑对已满的字节调用force(),然后丢弃它,然后从文件末尾开始创建一个新的字节

理想的解决方案是拥有一个永远不会超过容量的ByteBuffer,但我想检查一下这种情况并滚动字节缓冲区

那么您认为在上述情况下我应该调用force()吗?我可以放弃ByteBuffer并使用file.length()打开一个新的ByteBuffer,而不调用前一个ByteBuffer的force()吗

以下是我的刷新方法的代码:

        if (isMemoryMapped) {

            // first test if we are approaching the limit...
            int cap = buffer.capacity();
            int pos = buffer.position();
            float usage = (float) pos / cap;

            if (usage >= Log.getMappedBufferThreshold()) {
                // roll our buffer
                MappedByteBuffer mappedBuffer = (MappedByteBuffer) buffer;
                mappedBuffer.force();
                this.buffer = this.createMappedByteBuffer(outputFile, getMappedBufferSize());
            }

            // Then do NOTHING since this is a memory mapped buffer...

        }
调用MappedByteBuffer.force()的正当理由是什么

您需要立即将数据刷新到磁盘的任何时间,而不是等待缓冲区取消映射或应用程序退出

例如,使用MappedBytebuffer实现的事务数据库中的“提交”操作将要求您确保提交的数据立即写入光盘

[[更新

通过(重新)阅读MappedByteBuffer和FileChannel的javadocs,我的结论是调用
force()是谨慎的
应用程序关闭时也是如此……假设您希望刷新更新。据我所知,规范不保证数据将在
force()
调用的上下文之外刷新

结束]]

我的印象是,内存映射文件由操作系统“神奇地”发送到磁盘,您不必刷新它

那是不对的。如果JVM灾难性地死亡(或者是
kill-9
'ed),则无法保证映射的缓冲区将被刷新。如果操作系统本身死亡,则更具不确定性

force()
操作适用于需要确定性的情况。如果成功,您的更改将被保证在光盘上


您的示例可能合法,也可能不合法,这取决于应用程序的详细信息。例如,在shutdownhook中执行
force()
,听起来有点危险。如果应用程序因为检测到内部错误而关闭,那么刷新缓冲区实际上会造成更大的危害。。。取决于您对内存映射数据结构的设计程度。

首先想到的场景是:如果您正在编写某种服务器,并且需要日志记录,那么理想情况下,日志会定期刷新到磁盘,这样,如果服务器崩溃,日志数据不会丢失。@Corbin这听起来很合理,但实际上可能是错误的。我的印象是,内存映射文件由操作系统“神奇地”发送到磁盘,您不必刷新它。操作系统以某种方式为您管理这些。否则它和普通文件没有什么不同。不,它仍然是缓冲的。“强制将对此缓冲区内容所做的任何更改写入包含映射文件的存储设备。”@Corbin但正如Stephen在下面所说,唯一合法的原因是保护自己免受灾难性故障的影响,或者如果您需要确保(提交)立即将更改提交到磁盘。我正在通过上面的代码消除力。我可能在这方面是错的,但我相信这和正常情况一样。这实际上是一件好事,因为这意味着您可以覆盖这些内容,它们只会被过度写入内存,而不会被写入磁盘。我认为定期刷新日志的情况仍然适用,尽管我不太熟悉Java中内存映射的缓冲模型,因此它刷新缓冲区的频率可能比我想象的要高。谢谢。因此,在我上面的代码中,这并不是真正必要的,因为1)我没有紧迫感。2) 我不想保护自己免受灾难性故障(假设不包括未捕获的异常)@JohnPristine-在您决定不需要强制执行之前,您需要阅读javadocs关于何时以及如何将缓冲区更改刷新到磁盘的说明。然后根据规范所述编写代码。如果规范没有说明什么,那么谨慎的做法是假设最坏的情况。@StephenC我认为您不能得出结论,除非调用force(),否则在应用程序关闭之前永远不会编写MappedBytebuffer,这似乎暗示了您上面所说的。如果您不使用私有模式,我认为您有权期望磁盘上的数据更改将以合理的方式及时发生,就像正常写入一样:异步但及时。不过,我当然同意,如果您试图实现事务行为,则需要force()。@EJP-同样,您犯的错误与JohnPristine相同。我没有得出这样的结论。我说的是,规范没有对这个问题做任何说明,谨慎的做法是不要做出假设。我的意思是我们不确定会发生什么。。。没有在每个感兴趣的平台上测试行为或阅读代码。@StephenC恕我直言,你回答的第一句话假设的正是。我同意没有对其进行更严格的规定,但如果在应用程序退出之前不进行写入,则该工具在读/写情况下将没有实际用途。它显然是为了映射到一个虚拟内存实现中而设计的,我所遇到的所有实现都是及时写入的。