使用自定义堆的类似malloc的函数

6
如果我想使用自定义的预分配堆来构建类似 malloc 的功能,那么在 C 中最好的方法是什么?
我的问题具体在于,我有一个类似于内存的可映射设备已经被放置到我的地址空间中,但我需要一种更灵活的方式来使用这个内存,以便在时间上分配和释放对象。
我知道 malloc、free 和其他类似函数是用于在堆上执行此类分配的,但是否有任何方法可以使用此类函数提供的逻辑,同时为其动态行为提供自己的地址空间以操作相应的堆呢?

我可能误解了你的问题,但是在我看来,你似乎正在寻找类似于Linux的clone函数的东西,它类似于fork,但它允许你向子进程传递一个堆栈。 - Elias Van Ootegem
你需要什么样的内存管理呢?是完全通用的mallocfree吗?还是遵循堆栈规则(先分配的先释放)?也许你可以限制自己只分配单一大小的内存,并创建一个 - user395760
@delnan 我可能可以管理单一大小的分配(对象相当大,因此将其舍入到页面的开销很小),但堆栈可能不行。对象不太可能按可预测的顺序释放。我有点惊讶,鉴于所有逻辑都在标准库中,没有一种简单的方法来实现这一点,只是没有办法将它们指向自定义后端。无论如何,感谢您的评论。 - Vality
所以你可能正在寻找一个内存池库?你知道malloc和free经常使用靠近你分配的一些内存。如果这是一个可映射设备,最好不要这样做,如果这样做,它将被转移到其他地方。 - Alexander Oh
1
在Windows上,有自定义堆。它们可以用于多种用例,例如:创建所有对象具有相同大小的自定义堆(以帮助内部碎片化),或创建固定大小的堆(以防止应用程序使用超过其应该使用的内存)。Unix*世界尚未意识到这是一个非常有用的功能。 - BitTickler
显示剩余3条评论
2个回答

2

malloc及其相关函数是一组相当复杂的库函数。它们需要完成许多工作,例如跟踪堆中哪些部分正在使用等。

使用标准内存分配器malloc的一个相对简单的方法是通过自定义映射重新映射默认堆。

void * part_of_heap = memalign(sysconf(_SC_PAGESIZE), nbytes);
void * ret = mmap(part_of_heap, nbytes
             , PROT_READ | PROT_WRITE, MAP_FIXED, fd, 0);
if (ret == MAP_FAILED) {/* ... */}
free(part_of_heap);

现在,任何通过malloc放置在区域part_of_heap-part_of_heap+nbytes中的内容都会进入您自己映射的区域。这种做法是不被支持的,也不能保证任何分配都会实际进入该区域。
否则,您需要实现自己的内存分配器,并进行记账。一个链表可以作为入门级别的实现。我不知道有哪些开源的实现可以满足您的需求。

1

Boost.Interprocess具有适用于共享内存段的有状态分配器:它们可以重复使用于其他mmapped地址范围。

否则,您可能需要自己编写。按照复杂度递增的顺序,可以考虑以下选项:

  1. 简单的区域分配器:这几乎是微不足道的,但没有办法释放单个对象并重用其内存
  2. 简单的对象池分配器:对于几乎没有开销的固定大小对象有效(假设对象至少与指针一样大,您可以维护一个已释放对象的单向链表)
  3. 多个对象池的混合系统,适用于不同大小的对象(但每个池本身都是简单的固定大小实例)
  4. 某种类型的板块/泥浆分配器(多个固定大小的池共享大型固定大小板块的简单基础分配器)
  5. SLOB分配器
  6. 完整的malloc/free实现(有几个是开源的,因此您可以采取实现并剥离任何不需要的内容)。

哪些选项适合取决于您尚未提供的一些信息:

  • 对象大小
    • 如果您只需要分配一个或只有几个大小的对象,则对象池有效
    • 区域分配器不关心对象大小
    • 两者都不支持realloc
  • 对象寿命
    • 对象池通常支持任意malloc/free序列
    • 区域通常只允许一次性释放(因此只需将区域重置为空状态)。您可以修改此选项以允许后进先出的释放。
  • 空间/性能权衡
    • 完整堆实现可能是最慢和最复杂的,但也是最灵活的
    • SLOB更容易、更轻量级,但更容易受到碎片化的影响

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接