我的目标是确保在java中分配的数组是跨连续的物理内存分配的。我遇到的问题是,数组分配的页面在物理内存中往往不是连续的,除非我分配一个非常大的数组。

我的问题是:

  • 为什么一个非常大的数组确保在物理内存中连续的页面?
  • 有没有什么方法可以确保数组在物理内存中分配,而不涉及使数组变得很大?
  • 如何在不测量缓存命中/缓存未命中的情况下判断 Java 对象/数组存在于哪个页面或物理地址?

我不是在寻找答案来询问为什么我在 java 中这样做。我知道 C 会“解决我的问题”,并且我违背了 java 的基本性质。尽管如此,我这样做还是有充分的理由的。

答案不必保证始终有效。我正在寻找大多数时候有效的答案。对于任何一个理性的 Java 程序员都不会写出的创造性的、开箱即用的答案,可以加分。特定于平台(x86 32 位 64 位)是可以的。

有帮助吗?

解决方案

鉴于垃圾收集器在(逻辑)内存中移动对象,我认为您会不走运。

你能做的最好的事情就是使用 ByteBuffer.allocateDirect. 。(通常)GC 不会在(逻辑)内存中移动它,但它可能会移动到物理内存中,甚至分页到磁盘上。如果你想要更好的保证,你就必须使用操作系统。

话虽如此,如果您可以将页面大小设置为与堆一样大,那么所有数组必然在物理上连续(或交换)。

其他提示

不。物理上连续的内存需要与操作系统直接交互。大多数应用程序(包括 JVM)仅获取虚拟连续的地址。JVM 无法为您提供它无法从操作系统获得的东西。

另外,你为什么想要它?如果您正在设置 DMA 传输,那么您可能正在使用 Java 以外的技术。

背景知识:

现代 PC 中的物理内存通常是灵活的数量,位于可更换的 DIMM 模块上。它的每个字节都有一个物理地址,因此操作系统在引导期间确定哪些物理地址可用。事实证明,应用程序不直接使用这些地址会更好。相反,所有现代 CPU(及其缓存)都使用虚拟地址。存在到物理地址的映射表,但这不需要是完整的——通过使用未映射到物理地址的虚拟地址来启用到磁盘的交换。每个进程有一个表(具有不完整的映射)可以获得另一级别的灵活性。如果进程A有一个映射到物理地址X的虚拟地址,但进程B没有,那么进程B就无法写入物理地址X,我们可以认为该内存是进程A独占的。显然,为了安全起见,操作系统必须保护对映射表的访问,但所有现代操作系统都这样做。

映射表在页级别工作。页或物理地址的连续子集被映射到虚拟地址的连续子集。开销和粒度之间的权衡导致 4KB 页面成为常见的页面大小。但由于每个页面都有自己的映射,因此不能假设超出该页面大小的连续性。特别是,当页面从物理内存中逐出、交换到磁盘并恢复时,很可能最终会到达新的物理内存地址。程序不会注意到,因为虚拟地址没有改变,只有操作系统管理的映射表改变了。

我认为你会想使用 Sun.java.不安全.

可能有一些方法可以欺骗特定的 JVM 来执行您想要的操作,但这些方法可能很脆弱、复杂,并且很可能非常特定于 JVM、其版本、运行的操作系统等。换句话说,就是白费力气。

因此,在不了解您的问题的更多信息的情况下,我认为没有人能够提供帮助。一般来说,Java 中当然没有办法做到这一点,最多是在特定的 JVM 上。

建议替代方案:

如果您确实需要将数据存储在连续内存中,为什么不在一个小型 C 库中实现并通过 JNI 调用它呢?

照我看来。你还没有解释为什么

  • 原始数组在内存中不是连续的。我不明白为什么它们在虚拟内存中不连续。(参见对象数组不太可能使其对象在内存中连续)
  • 物理内存(RAM,即 RAM)中不连续的数组随机存取存储器)会有显着的性能差异。例如应用程序性能的可测量差异。

看起来您确实在寻找一种低级方法来分配数组,因为您习惯于在 C 中执行此操作,并且性能是需要执行此操作的要求。

顺便提一句:使用 getDouble()/putDouble() 访问 ByteBuffer.allocateDirect() 可能比仅使用 double[] 更慢,因为前者涉及 JNI 调用,而后者可以优化为根本不调用。

使用它的原因是为了在 Java 和 C 空间之间交换数据。例如蔚来来电。只有当读/写保持在最低限度时它才表现良好。否则你最好使用 Java 领域的东西。

IE。除非你清楚自己在做什么并且 为什么 当你这样做时,你最终可能会得到一个可能会让你感觉更好的解决方案,但实际上它比简单的解决方案更复杂并且性能更差。

笔记 这个答案 到一个相关的问题,该问题讨论了 System.identityHashCode() 和对象内存地址的标识。最重要的是,您可以使用默认的数组 hashCode() 实现来识别数组的原始内存地址(需适合 int/32 位)

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top