【问题标题】:Implement Virtual Memory with Memory Mapped Files使用内存映射文件实现虚拟内存
【发布时间】:2011-12-31 10:56:41
【问题描述】:

是否可以像这样包装内存映射文件?

TVirtualMemoryManager = class
public
  function  AllocMem (Size : Integer) : Pointer;
  procedure FreeMem (Ptr : Pointer);
end;

由于内存映射文件 API 函数都采用偏移量,我不知道如何管理内存映射文件中的空闲区域。我唯一的想法是实现某种基本的内存管理(维护不同块大小的空闲列表),但我不知道这会有多有效。

编辑:我真正想要的是(正如大卫向我明确表示的那样):

IVirtualMemory = interface
  function  ReadMem (Addr : Int64) : TBytes;
  function  AllocateMem (Data : TBytes) : Int64;
  procedure FreeMem (Addr : Int64);
end;

我需要在虚拟内存中存储连续的字节块(每个相对较小),并能够使用 64 位地址将它们读回内存。大多数时候访问是只读的。如果需要写入,我会使用FreeMem,后跟AllocMem,因为大小会有所不同。

我想要一个带有这个接口的内存映射文件的包装器。在内部,它有一个内存映射文件的句柄,并在每个ReadMem 请求上使用MapViewOfFileAddr 64 位整数只是内存映射文件的偏移量。悬而未决的问题是如何分配这些地址 - 我目前保留一份我维护的空闲块列表。

【问题讨论】:

  • “虚拟内存”是什么意思?系统已经为您做到了。
  • 我想绕过 2/3/4 GB 内存限制,并希望虚拟内存由文件(本例中为页面文件)支持。
  • 在这种情况下,您需要与此不同的界面。您需要一个能够让您超过地址空间限制的接口,而这不会。
  • 那你能提出一个接口吗?我知道你在工作中会做一些数据密集型的工作,所以也许你有这方面的经验?
  • @Smasher 如果 FreeMems 很少,那么忽略它们并将内存视为无限!这将它从一项艰巨的工作变成了一项微不足道的工作。

标签: windows delphi delphi-xe memory-mapped-files virtual-memory


【解决方案1】:
  1. 您的建议“在内部它有一个内存映射文件的句柄并在每个 ReadMem 请求上使用 MapViewOfFile”将只是浪费 CPU 资源,恕我直言。

  2. 值得一提的是,您的GetMem / FreeMem 要求将无法突破 3/4 GB 的障碍。由于在调用FreeMem 之前,所有分配的内存都将映射到内存中,因此您将缺少内存空间,就像使用常规的 Delphi 内存管理器一样。你能做的最好的就是依赖FastMM4,并改变你的程序以减少它的内存使用。

  3. 恕我直言,您必须更改/更新您的规范。例如,您的“更新”问题听起来就像一个常规的存储问题。

您想要的是能够为您的应用程序分配超过 3/4 GB 的数据。在我们的SynBigTable 开源单元中,您已经实现了此类功能。这是一个在纯 Delphi 中快速而轻便的NoSQL 解决方案。

它能够创建任意大小的文件(仅限 64 位),然后根据请求将每条记录的内容映射到内存中。如果可能,它将使用文件的内存映射。您可以使用TSynBigTable 方法非常直接地实现您的接口:ReadMem=Get, AllocMem=Add, FreeMem=Delete。 ID 将是您的类似pointer 的值,并且将使用RawByteString 而不是TBytes

您可以使用整数 ID 或字符串 ID 访问任何数据块,甚至可以使用复杂的字段布局(在记录内,或作为内存中的元数据 - 包括索引和快速搜索)。

或者依赖于常规的嵌入式 SQL 数据库。例如,SQLite3 非常擅长处理 BLOB 字段,并且能够存储大量数据。为最常用的记录提供简单的内存缓存机制,这可能是一个强大的解决方案。

【讨论】:

  • 这个想法大概是在不再需要内存时取消映射内存。
  • @DavidHeffernan 这就是为什么即使是问题中的新 ReadMem 方法接口也不够用。使用存储库将依赖于根据请求分配内存。正如我的第一点所说,映射和取消映射是有代价的——API 不是为小内存块设计的——例如minimum x86 paging is 4 KB,每个内存映射都需要额外的内存(Windows 句柄、额外的内存结构...... )。
  • @DavidHeffernan 这个问题的问题是技术设计已经固定 - 恕我直言是错误的。内存映射不用作建议的 OP。它不会有效率。因此,我建议从另一个方向解决原始软件需求:处理大量内存块,而不受 32 位程序的 3/4 GB 内存限制。这需要一个常规的存储引擎(NoSQL 或 SQL)。有时依赖现有库是一个好主意,而且可以节省时间。
  • 当然内存读完会解映射,所以ReadMem就足够了。更高层次的想法是让对象引用知道当引用计数降至零时如何序列化和交换自身。我有一个巨大的内存对象层次结构要处理,这只是我正在评估的一个想法。因此,感谢您对此的意见。使用表格基本上意味着放弃我想避免的对象层次结构。
  • @Smasher 您可以将对象层次结构存储在表中,每个对象使用一个 ID。只需创建一个对象的链接列表,使用 ID 来嵌套它们。您可以像指针一样看到 ID。像我们的 SynBigTable 这样的 NoSQL 引擎的兴趣在于记录大小不是固定的。它将使用RawByteString,就像您的界面的TBytes 一样(在这里,您是对的,ReadMem 就足够了)。您可以使用 TSynBigTable 方法非常直接地实现您的接口:ReadMem=Get、AllocMem=Add、FreeMem=Delete。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-23
  • 2015-09-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多