重载新运算符以将对象存储在mmap'd文件中

我有一个Linux C ++程序有相当大的内存要求。 大部分的内存只被less数几个类所占用,而且访问的次数也相当less。 我想将这些类从主内存移动到基于磁盘的存储,同时尽可能less地改变现有的代码。

这个想法是覆盖这些对象的new运算符,并将它们分配到一个mmap()内存区域。 这样,我的代码修改保持非常有限,程序的其余部分可以愉快地访问这些对象,而不知道任何改变,内核将确保我需要的对象在内存中,而其他的都在磁盘上。 我知道这是非常相似的交换如何工作,但交换分区通常太小,我的程序需要什么。

我有一些问题:

  • 这是一个非常糟糕的主意吗? 你知道更好的事情来实现吗?
  • 我是否需要事先分配最大的文件大小,并要求将所有这些空间分配到磁盘上? 如果是这样,将映射到稀疏文件的帮助?
  • 我不想写我自己的堆分配器。 我可以使用现有的吗?
  • 当我的程序完成后,mmap'd文件将被删除。 这意味着我不想将任何页面写入磁盘, 除非内核实际上将它们从内存中删除。 有没有像一个懒惰的标志,以实现这一目标,或者是这是自动的?

依次查看每个问题

  • 这是一个非常糟糕的主意吗? 你知道更好的事情来实现吗?

它不是很清楚你希望通过这个实现什么。 Linux已经支持交换空间使用的内存(所以如果你的数据超过物理内存,一些将被交换到磁盘)。 您是否遇到地址空间不足的问题,或由于分页过多而缓慢运行? 使用mmap支持的商店也不会真的影响。

  • 我是否需要事先分配最大的文件大小,并要求将所有这些空间分配到磁盘上? 如果是这样,将映射到稀疏文件的帮助?

是的,你需要这个文件和你所在的空间一样大。 但是,您可以从小文件/ mmap开始,然后根据需要增大文件(和mmap其他页面)。 您也可以使用稀疏文件,以便在写入页面之前不使用磁盘空间。

  • 我不想写我自己的堆分配器。 我可以使用现有的吗?

有堆使用mmap支持的存储的管理器。 我看过Doug Lea malloc的版本,以及其他各种各样的bibop分配器。

  • 当我的程序完成后,mmap'd文件将被删除。 这意味着我不想将任何页面写入磁盘,除非内核实际上将它们从内存中删除。 有没有像一个懒惰的标志,以实现这一目标,或者是这是自动的?

在这种情况下,你可以只使用MAP_ANON,而根本没有文件。 但是,这又回到了第一个问题,因为这实质上是复制了系统malloc(和new)所做的事情。 事实上,在一些操作系统(Solaris?)上,这正是系统malloc所做的。 我以前见过的基于mmap的malloc主要是为了持久化存储(所以文件会在进程退出后保留下来,并在重启时重新映射)。

我可以想想你想采取的方法的一些问题,所以这不是一个答案。

  1. 当你“交换”一些东西的时候,也就是说你所面临的问题是消耗太多的内存来保持对象的周围,所以你什么时候删除它们(有效地取消映射)? 即做出与您的操作系统的内存管理器相同的决定?
  2. 尽管你可能能够将类的二进制表示存储在一个mmaped块中,但如果这个类不是POD,那么“交换”过程就不会达到你所期望的(例如,如果有成员是堆分配 – 发生在他们身上?)
  3. mmap的内存仍然会计入你的过程,因此,你的问题不会消失…

我认为你最好的选择就是看你的设计,并考虑什么时候需要这些课程以及需要多长时间。 在不需要的时候构建,使用和丢弃 – 构建起来是否昂贵? 也许他们会更便宜地序列化到一些本地文件和重建(当我说序列化,我的意思不是简单的内存拷贝!)

最好的选择可能是指定你的程序需要配置最小的交换量,而不是试图用mmap()来模拟更多的交换。 尤其是,最后一点不可能被克服 – 文件支持映射中的脏页通常优先写出。