【问题标题】:MappedByteBuffer clear cached PagesMappedByteBuffer 清除缓存的页面
【发布时间】:2014-04-19 11:06:25
【问题描述】:

我遇到了 MappedByteBuffer 的问题,特别是它在内部是如何工作的。我理解它的方式缓存完全由操作系统完成。因此,如果我从文件中读取(使用 MappedByteBuffer),操作系统将从硬盘驱动器读取整个页面并将页面保存在 RAM 中,以便在再次需要时更快地访问。这也允许为访问同一文件的多个应用程序/进程提供共享缓存。这是正确的吗?

如果是这样,如何使这个缓存失效?只是重新初始化映射对象不应该工作。我编写了一个从硬盘驱动器读取大量数据的应用程序。我需要做一些基准测试,所以我需要在需要时清除这个缓存。我尝试使用“echo 3 > /proc/sys/vm/drop_caches”,但这并没有什么不同,所以我认为它不起作用。

【问题讨论】:

  • 这取决于操作系统;看来您在这里使用的是 Linux,但您真正应该做的是 .force() 并取消映射,然后再次映射。
  • docs.oracle.com/javase/6/docs/api/java/nio/channels/… 说“映射一旦建立,就不会依赖于用于创建它的文件通道。特别是关闭通道对映射的有效性没有影响。”
  • @Karamba 保存到文件的映射后,它会保持打开状态,直到您调用 close() 并且所有映射都已清除。
  • 你能告诉我在规范中哪里可以找到这个吗?我只看到以下内容:docs.oracle.com/javase/7/docs/api/java/nio/channels/… - “映射一旦建立,不依赖于用于创建它的文件通道。特别是关闭通道对映射的有效性没有影响。”因此,我看不到关闭 File/FileChannel 如何帮助从 MappedByteBuffer 回收 RAM。
  • 正如所写,这似乎是一个“X-Y”问题:你想做 X,并且你认为 Y 是解决它的最佳方法,所以你问如何做 Y。你想要完成的真正的“X”?换句话说,你打算用你的基准来演示/验证/测试什么?

标签: java mappedbytebuffer


【解决方案1】:

这还允许为访问同一文件的多个应用程序/进程提供共享缓存。这是正确的吗?

这就是它在 Linux、Windows 和 MacOS 上的工作方式。在其他操作系统上,可能是相同的。

如果是这样,如何使这个缓存失效?

删除该文件,它将不再有效。

我需要做一些基准测试,所以我需要在需要时清除这个缓存。

这就是操作系统的用途。如果您需要强制缓存无效,这很棘手并且完全依赖于操作系统。

我尝试使用“echo 3 > /proc/sys/vm/drop_caches”,但这并没有什么不同,所以我认为它不起作用。

它可能对您的基准测试没有影响。我建议你看看/proc/meminfo

Cached:           588104 kB
SwapCached:          264 kB

顺便说一句,如果您想取消映射 MappedByteBuffer,我会执行以下操作

public static void clean(ByteBuffer bb) {
    if (bb instanceof DirectBuffer) {
        Cleaner cl = ((DirectBuffer) bb).cleaner();
        if (cl != null)
            cl.clean();
    }
}

这也适用于直接 ByteBuffers,但可能不适用于 Java 9,因为此接口将被删除。

【讨论】:

  • 删除文件是没有选择的。我将尝试查看 /proc/meminfo
  • 假设我在我的应用程序中运行了一次。调用 clean() 后,下次运行时不会使用第一次运行的缓存页面?
  • @Karamba 如果您使用drop_caches,则此时不会保留任何内容。在top 中,您可以看到缓存数据很少。看来内核为自己的目的保留了一些页面。一个好的测试是在测试之前和之后执行vmstat -s 并获取差异。这将告诉您自启动以来执行的总 IO。如果您获得相同数量的 IO,则您知道读取/写入的数量是相同的。
  • 对不起,我还是不明白。所以 drop_caches 应该适用于不使用以前运行的缓存页面?
  • @Karamba 它应该清除所有缓存的数据。它可能不会清除映射的数据,但我没有看到任何说明是这种情况的。
【解决方案2】:

已知的可悲问题(JDK 中仍未解决):http://bugs.java.com/view_bug.do?bug_id=4724038

但即使没有公开的 API,也有一个危险的解决方法(使用风险自负):https://community.oracle.com/message/9387222

另一种方法是不使用巨大的 MappedByteBuffers 并希望它们最终会被垃圾收集。

如果需要不同的程序来映射这个文件,使用他们自己的 MappedByteBuffer 副本,MapMode.PRIVATE 可以提供帮助。

希望对您有所帮助。

【讨论】:

  • 我不认为他试图取消映射,而是清除磁盘缓存以获得可重现的基准测试结果。
  • 你能解释一下,'清除磁盘缓存'是什么意思,据我所知,MappedByteBuffer 直接映射到 RAM,
  • 是的,我只想拥有可复制的基准。我真的不关心立即取回使用过的 RAM。我希望以前运行的缓存页面不再使用。
  • 您需要的是 MapMode.PRIVATE 吗?更新了答案。
猜你喜欢
  • 1970-01-01
  • 2023-03-03
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-12
  • 2015-02-13
相关资源
最近更新 更多