【问题标题】:malloc like function using custom heap使用自定义堆的类似 malloc 的函数
【发布时间】:2014-06-14 00:41:42
【问题描述】:

如果我希望使用自定义的预分配堆构建类似 malloc 的功能,那么 C 语言中的最佳方法是什么?

我的具体问题是我有一个可映射(类似内存)的设备,它已被放置在我的地址空间中,但我需要获得一种更灵活的方式来使用此内存来存储将被分配和释放的对象随着时间的推移。

我知道 malloc、free 和其他类似的函数用于在堆上执行这种分配,但是有没有办法在提供我自己的地址空间的同时使用这种函数提供的逻辑来实现其动态行为作为有问题的堆运行?

【问题讨论】:

  • 我可能误解了你的问题,但在我看来你正在寻找类似 @​​987654321@ 的东西,它类似于 fork,但它允许你将堆栈传递给那个子进程
  • 嗯,你需要什么样的内存管理? malloc & free 的全部通用性?或者你是否遵守堆栈规则(先分配,先释放)?也许您可以限制自己分配单一大小并创建一个 pool
  • @EliasVanOotegem 感谢您的评论,不幸的是,这并不是我想要的。本质上,我有一个自定义内存映射设备,我希望将其用作内存分配的“堆”。我正在寻找一种在此设备上运行内存分配器而不是普通堆的方法。这不是在这种情况下允许 IPC,只是因为我需要将数据存储在特定设备上。
  • @delnan 我可能可以管理单一大小的分配(对象非常大,因此从四舍五入到一页的开销很小)但是堆栈可能不太好。对象不太可能以可预测的顺序被释放。考虑到标准库中的所有逻辑,我有点惊讶,没有一种相当简单的方法可以做到这一点,只是无法将它们指向自定义后端。不过感谢您的评论。
  • 在 Windows 上,有自定义堆。它们可用于多种用例,例如:创建所有对象具有相同大小的自定义堆(以帮助解决内部碎片)或创建固定大小的堆(以防止应用程序使用比预期更多的内存。Unix * 世界尚未认识到这是一个非常有用的功能。

标签: c linux memory memory-management heap-memory


【解决方案1】:

malloc 和 family 是一组相当复杂的库函数。他们做了大量的簿记工作,比如堆的哪些部分正在使用等等。

使用标准内存分配器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 中的东西都将进入您自己的映射区域。但是,这是不受支持的,并且不能保证任何分配都会真正到达那里。

否则,您将需要实现自己的内存分配器,它必须进行簿记。对于初学者来说,链表就可以了。我知道没有可以满足您需求的开放式实施。

【讨论】:

    【解决方案2】:

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

    否则,您可能需要自己滚动。按照复杂度递增的顺序,您可以考虑:

    1. 一个简单的 arena 分配器:这几乎是微不足道的,但无法释放单个对象并重用它们的内存
    2. 一个简单的对象池分配器:这适用于几乎没有开销的固定大小对象(假设对象至少和指针一样大,您可以维护一个已释放对象的单链表)
    3. 混合系统具有多个不同大小的对象池(但每个池都是一个简单的固定大小实例)
    4. 某种slab/slub 分配器(多个固定大小的池共享一个简单的大型固定大小slab 的底层分配器)
    5. SLOB 分配器
    6. 一个完整的 malloc/free 实现(有几个是开源的,因此您可以采用一个实现并删除任何您不需要的东西)。

    哪些是合适的取决于你没有提供的一些信息:

    • 对象大小
      • 如果您只有一个或几个大小的对象要分配,则对象池可以工作
      • 竞技场分配器不关心对象大小
      • 都不支持realloc
    • 对象生命周期
      • 对象池通常支持任意 malloc/free 序列
      • arenas 通常只允许一次性释放(因此您只需将 arena 重置为空状态)。您可以修改它以允许 LIFO 解除分配。
    • 空间/性能权衡
      • 完整的堆实现可能是最慢和最复杂的,但也是最灵活的
      • SLOB 更简单,重量更轻,但更容易受到碎片化的影响

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-27
      • 1970-01-01
      • 2015-10-29
      • 2020-12-06
      • 2012-08-08
      • 1970-01-01
      相关资源
      最近更新 更多