这是我的问题:我需要管理我的程序无法读取或写入的远程连续缓冲区中的内存 . 它需要具有malloc()/ free()语义,并支持设置最小对齐和碎片避免(尽可能) . 由于我无法直接读取或写入此缓冲区,因此我需要使用本地结构来管理所有分配 .
我已经在使用boost了,所以如果可以按摩内部的东西来做到这一点,那就太好了 . 但是,我并不反对使用C库或类似的东西 .
举个例子,我需要一个非IPC版本的:
boost::interprocess::basic_managed_external_buffer<
char,
boost::interprocess::rbtree_best_fit<
boost::interprocess::mutex_family,
boost::interprocess::offset_ptr<void>,
SOME_ALIGNMENT>,
boost::interprocess::iset_index>
最好使用malloc / free语义而不是new / delete但是没有实际读取或写入底层缓冲区(并将所有分配信息/数据结构保存在单独的缓冲区中)
有任何想法吗?
附:我不希望boost :: interprocess示例误导,我只是熟悉接口,所以以它为例 . 应用程序实际上不是进程间的,分配器只能在我的应用程序中使用 .
具体来说,我希望能够管理一个16GB的外部缓冲区,其分配大小从128字节一直到512MB . 这是严格的64位代码,但即便如此我更喜欢指针类型作为模板参数,所以我可以明确地使用uint64_t .
2 回答
我不知道,除了我的帽子之外,我还不知道任何可以使用的 jar 头实现 . 但是,使用C标准库中的花园种类容器,这似乎并不特别难以实现 .
我建议使用两个
std::map
和一个std::multimap
的简单方法 . 假设bufaddr_t
是一个不透明的整数,表示外部缓冲区中的地址 . 由于我们讨论的是16 gig缓冲区,因此它必须是64位地址:同样适用于已分配块的大小 .
我想,只要不透明数据类型具有严格的弱排序,您就可以使用
memblockaddr_t
的其他内容 .第一部分很简单 . 跟踪所有已分配的块:
因此,当您在外部缓冲区中成功分配一块内存时,请将其插入此处 . 当您希望释放一块内存时,在此处查找已分配块的大小,并删除映射条目 . 很简单 .
但那当然不是整个故事 . 现在,我们需要跟踪可用的未分配内存块 . 我们这样做:
unallocated
是外部缓冲区中所有未分配的块的集合,由块大小键入 . 关键是块大小 . 因此,当您需要分配特定大小的一块内存时,您可以简单地使用lower_bound()
方法(或upper_bound()
,如果您愿意)立即找到第一个块,其大小至少是您想要分配的大小 .当然,由于你可以有许多相同大小的块,
unallocated
必须是std::multimap
.此外,
unallocated_lookup
是一个由每个未分配的块的地址键入的映射,它为unallocated
中的块块条目提供了迭代器 . 为什么你需要它会在一瞬间变得清晰 .所以:
使用单个条目初始化一个新的,完全未分配的缓冲区:
然后:
要分配一个块,请使用我上面提到的lower_bound()/ upper_bound()方法来查找至少一个大的第一个未分配的块,并从
unallocated
和unallocated_lookup
中删除它的条目 . 如果需要解除分配(下面的步骤3) . 最后,将其插入allocated
数组,以便记住分配的块的大小 .要解除分配块,请在
allocated
数组中查找,获取其大小,将其从allocated
数组中删除,然后:将其插入
unallocated
和unallocated_lookup
,类似于插入初始未分配块的方式,请参见上文 .但你还没有完成 . 然后,您必须使用
unallocated_lookup
在内存缓冲区中轻松查找前面未分配的块和以下未分配的块 . 如果它们中的任何一个或两个紧邻新释放的块,则必须将它们合并在一起 . 这应该是一个非常明显的过程 . 您可以简单地完成从unallocated
和unallocated_lookup
正式删除相邻块的动作,然后释放单个合并的块 .这是
unallocated_lookup
的真正目的,能够轻松地合并连续的未分配块 .据我所知,上述所有操作都具有对数复杂性 . 它们完全基于具有对数复杂性的
std::map
和std::multimap
方法,而不是其他任何方法 .最后:
取决于您的应用程序's behavior, you can easily tweak the implementation to internally round up the size of an allocated chunk to whatever multiple you wish. Or adjust the allocation strategy -- allocate from the smallest chunk that'足够大以满足分配请求,或者只是从大的未分配的块分配(简单,使用
end()
来查找它)等等...这是滚动您自己的实现的一个优点 - 您将总是有更大的灵活性来调整您自己的实现,然后您通常会有一些固定的外部库 .
我正在发布我们实际上正在做的事情的更新 . 我最终实现了自己的远程内存分配器(下面的源代码) . 它在精神上类似于answer Sam suggests,但是在释放,加入等时使用boost侵入式RB树来避免一些log(N)查找 . 它在很多方面可能不太理想,但它对我们需要的东西运行得很好去做 . 如果您发现错误,请告诉我 .