4

问候大家,

我想通过内存映射文件实现 Java 对象的透明持久性(利用 OS 分页/交换机制)。

我的问题是:如何将 Java 对象移动到我的内存映射块?另外,我怎样才能强制一个新的对象实例驻留在这样的块中?

众所周知,内存映射块可以看作是一个字节数组,而我在这里真正要问的是如何将 Java 对象的地址空间与此类数组之一重叠?这样我们仍然可以在操作系统透明地处理持久性(写入脏页)时通过对象操作数据。

如果 Java 不允许我这样做,你会建议我使用哪种跨平台和垃圾收集 OO 语言?

谢谢大家。

4

3 回答 3

3

这是不可能的。运行时不允许这样做有几个很好的理由。

  • 对象的内存布局是 JVM 内部结构的一部分。每个 JVM 都可以自行决定如何布局对象。此布局可以随版本更改。当您将对象内存映射到文件时,您会遇到麻烦。当对象布局发生变化时会发生什么?崩溃,更新文件,变魔术?最后,将对象映射到文件需要指定一个固定的对象布局。
  • 如果添加/删除字段会发生什么?那么对象布局肯定发生了变化。您不能使用旧的内存布局对文件进行内存映射。
  • 一个对象还有其他信息,比如虚函数调用的 VTable、锁定状态的字段等。你也想要映射它们吗?可能不是,因为那是内部运行时状态。因此,您需要始终忽略一些字节或拆分对象。这会使内存布局变得极其复杂。
  • 垃圾收集器通过移动对象来压缩内存以最小化碎片。因此,物体需要有一个“固定”机制。(出于互操作原因,这在 .NET 中是可能的)
  • 垃圾收集器分代工作。如果首先在年轻代上分配一个对象。随着它的生存,它被转移到其他世代。内存映射对象需要异常。

由于所有这些原因,您无法对 Java/.NET 对象进行内存映射。支持这样的特性会使 JVM/CLR 变得极其复杂。

JVM/CLR 仍然允许您以类似数组的抽象形式访问 Memory-Mapped 文件,您可以在其中写入/读取字节。在此之上,您可以实现您的持久性机制。从简单的序列化到复杂的数据库。有些对象数据库非常接近提供透明的持久性。然后对象的行为类似于持久数据结构/内存映射对象。

于 2010-06-16T18:09:33.250 回答
3

您可以做到这一点的唯一方法是使用您自己的 Java VM 并添加此功能。当然,您将编写的代码不是 Java,而是实现 VM 的语言。很久以前,Gemstone 将这种方法用于他们的对象数据库引擎。

今天的对象数据库(我正在研究一个。)不以这种方式做事。增强字节码以跟踪字段访问并使用反射或注入方法将对象转换为某种序列化形式要简单得多。这表现相当不错。如果要支持查询,则无论如何都必须使用单个字段值来索引它们。

对我们来说,为我们想要运行的所有平台维护一个虚拟机是不可行的。我们也无法说服认真的客户将他们的整个(银行)应用程序依赖于我们定制的 VM。

如果您对生成基于 Java VM 的解决方案非常感兴趣:曾经有一个有趣的 Java 正交透明持久性研究项目,称为“Forest”。您也许可以找到旧论文甚至源代码。

如果您正在寻找一种不同的语言来直接从内存中获取“对象”:C++ 会让您这样做。有一些用 C++ 编写的旧对象数据库使用这种方法。...但是,这太疯狂了,使用页面错误来加载对象。这类对象数据库产生了不良形象。我希望我们能很快再次扭转局面。

于 2010-06-17T00:48:30.173 回答
1

你不能。

Java 在设计上强制执行类型安全和引用完整性。也就是说,如果我有一个引用类型 T 的字段,我知道它指向 T 的一个实例。(排除类型擦除引入的堆污染)。这与“不安全”的语言(例如 C++)形成对比,在 C++ 中,引用很可能指向无效位置,而该引用可能会导致“内存损坏”。

如果 Java 允许将 byte[] 视为Object,则无法保证这种引用完整性。

于 2010-06-16T18:32:59.313 回答