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

时间:2022-07-11 07:19:12

What would be the best approach in C if I wish to construct malloc like functionality with a custom pre-allocated heap?

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

My specific issue here is that I have a mmap-able (memory like) device which has been placed into my address space but I need to attain a more flexible way of using this memory to store objects which will be allocated and freed over time.

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

I know that malloc, free and the other similar functions are used to perform this kind of allocation on the heap but is there any way to use the logic provided by this kind of function for its dynamic behaviour while providing my own address space to operate as the heap in question?

我知道malloc,*和其他类似的功能是用来执行这种分配在堆上但有什么办法可以使用这类提供的逻辑函数的动态行为,同时提供我自己的地址空间中运行的堆的问题吗?

2 个解决方案

#1


1  

Boost.Interprocess has stateful allocators suitable for shared memory segments: they may be re-usable for other mmapped address ranges too.

提振。进程间具有适合共享内存段的有状态分配器:它们也可以用于其他映射地址范围。

Otherwise, you may need to roll your own. In increasing order of complexity, you could consider:

否则,你可能需要自己动手。为了增加复杂性,你可以考虑:

  1. a simple arena allocator: this is almost trivial, but has no way to free individual objects and reuse their memory
  2. 一个简单的arena分配器:这几乎是微不足道的,但是没有办法释放单个对象并重用它们的内存。
  3. a simple object pool allocator: this works for fixed-size objects with almost no overhead (assuming the object is at least as large as a pointer, you can maintain a singly-linked list of freed objects)
  4. 一个简单的对象池分配器:它适用于几乎没有开销的固定大小对象(假设对象至少和一个指针一样大,您可以维护一个被释放的对象的单链接列表)
  5. a hybrid system with multiple object pools for different sizes (but each pool is individually a simple fixed-size instance)
  6. 一个具有多个不同大小的对象池的混合系统(但是每个池都是单独的一个简单的固定大小的实例)
  7. some kind of slab/slub allocator (multiple fixed-size pools sharing a simple underlying allocator of large fixed-size slabs)
  8. 某种板/块分配器(多个固定大小的池共享一个简单的大型固定大小板的底层分配器)
  9. a SLOB allocator
  10. 一个懒汉分配器
  11. a full malloc/free implementation (several are open source, so you can take an implementation and rip out anything you don't need).
  12. 一个完整的malloc/free实现(几个是开源的,所以您可以执行并删除任何您不需要的东西)。

Which of those are suitable will depend on some information you haven't given:

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

  • object size
    • object pools work if you have only one, or only a few, sizes of object to allocate
    • 如果只有一个或几个要分配的对象大小,则对象池可以工作
    • arena allocators don't care about object size
    • 竞技场配置器不关心对象大小。
    • neither support realloc
    • 既不支持realloc
  • 对象大小对象池可以工作,如果您只有一个或几个对象的大小来分配竞技场分配器不关心对象的大小,也不支持realloc
  • object lifetime
    • object pools generally support arbitrary malloc/free sequences
    • 对象池通常支持任意的malloc/free序列
    • arenas usually allow deallocation only all-at-once (so you just reset the arena to an empty state). You could modify this to allow LIFO deallocation.
    • 竞技场通常只允许一次性释放(所以你只需将竞技场重置为空状态)。您可以修改它以允许LIFO释放。
  • 对象生存期对象池通常支持任意的malloc/free序列阿里纳斯通常只允许一次性的释放(因此您只需将竞技场重置为空状态)。您可以修改它以允许LIFO释放。
  • space/performance tradeoffs
    • the full heap implementation will probably be the slowest and most complex, but is also the most flexible
    • 完整堆实现可能是最慢、最复杂的,但也是最灵活的
    • SLOB is easier and lighter-weight, but suffers more from fragmentation
    • SLOB更容易,重量更轻,但更容易破碎
  • 全堆实现的空间/性能权衡可能是最慢、最复杂的,但也是最灵活的SLOB更容易、更轻,但更容易受到碎片化的影响

#2


2  

malloc and family is a rather complex set of library functions. They do a lot of bookkeeping like which parts of the heap are in use and such.

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

A relatively easy way to use the standard memory allocator malloc is to remap the default heap with your custom mapping.

使用标准内存分配器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);

Now anything that is placed in the area part_of_heap-part_of_heap+nbytes by malloc will go into your own mapped area. This is unsupported though and will not guarantee that any allocations will actually go there.

现在,malloc放置在area part_of_heap-part_of_heap+nbytes中的任何东西都将进入您自己的映射区域。但这是不受支持的,也不能保证任何资金分配都能实现。

Otherwise you would need to implement your own memory allocator, which has to do bookkeeping. A linked list would do for starters. I know of no open implementation that would serve your needs.

否则,您将需要实现自己的内存分配器,它必须进行簿记。一个链表可以作为开始。我知道没有任何开放的实现可以满足您的需要。

#1


1  

Boost.Interprocess has stateful allocators suitable for shared memory segments: they may be re-usable for other mmapped address ranges too.

提振。进程间具有适合共享内存段的有状态分配器:它们也可以用于其他映射地址范围。

Otherwise, you may need to roll your own. In increasing order of complexity, you could consider:

否则,你可能需要自己动手。为了增加复杂性,你可以考虑:

  1. a simple arena allocator: this is almost trivial, but has no way to free individual objects and reuse their memory
  2. 一个简单的arena分配器:这几乎是微不足道的,但是没有办法释放单个对象并重用它们的内存。
  3. a simple object pool allocator: this works for fixed-size objects with almost no overhead (assuming the object is at least as large as a pointer, you can maintain a singly-linked list of freed objects)
  4. 一个简单的对象池分配器:它适用于几乎没有开销的固定大小对象(假设对象至少和一个指针一样大,您可以维护一个被释放的对象的单链接列表)
  5. a hybrid system with multiple object pools for different sizes (but each pool is individually a simple fixed-size instance)
  6. 一个具有多个不同大小的对象池的混合系统(但是每个池都是单独的一个简单的固定大小的实例)
  7. some kind of slab/slub allocator (multiple fixed-size pools sharing a simple underlying allocator of large fixed-size slabs)
  8. 某种板/块分配器(多个固定大小的池共享一个简单的大型固定大小板的底层分配器)
  9. a SLOB allocator
  10. 一个懒汉分配器
  11. a full malloc/free implementation (several are open source, so you can take an implementation and rip out anything you don't need).
  12. 一个完整的malloc/free实现(几个是开源的,所以您可以执行并删除任何您不需要的东西)。

Which of those are suitable will depend on some information you haven't given:

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

  • object size
    • object pools work if you have only one, or only a few, sizes of object to allocate
    • 如果只有一个或几个要分配的对象大小,则对象池可以工作
    • arena allocators don't care about object size
    • 竞技场配置器不关心对象大小。
    • neither support realloc
    • 既不支持realloc
  • 对象大小对象池可以工作,如果您只有一个或几个对象的大小来分配竞技场分配器不关心对象的大小,也不支持realloc
  • object lifetime
    • object pools generally support arbitrary malloc/free sequences
    • 对象池通常支持任意的malloc/free序列
    • arenas usually allow deallocation only all-at-once (so you just reset the arena to an empty state). You could modify this to allow LIFO deallocation.
    • 竞技场通常只允许一次性释放(所以你只需将竞技场重置为空状态)。您可以修改它以允许LIFO释放。
  • 对象生存期对象池通常支持任意的malloc/free序列阿里纳斯通常只允许一次性的释放(因此您只需将竞技场重置为空状态)。您可以修改它以允许LIFO释放。
  • space/performance tradeoffs
    • the full heap implementation will probably be the slowest and most complex, but is also the most flexible
    • 完整堆实现可能是最慢、最复杂的,但也是最灵活的
    • SLOB is easier and lighter-weight, but suffers more from fragmentation
    • SLOB更容易,重量更轻,但更容易破碎
  • 全堆实现的空间/性能权衡可能是最慢、最复杂的,但也是最灵活的SLOB更容易、更轻,但更容易受到碎片化的影响

#2


2  

malloc and family is a rather complex set of library functions. They do a lot of bookkeeping like which parts of the heap are in use and such.

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

A relatively easy way to use the standard memory allocator malloc is to remap the default heap with your custom mapping.

使用标准内存分配器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);

Now anything that is placed in the area part_of_heap-part_of_heap+nbytes by malloc will go into your own mapped area. This is unsupported though and will not guarantee that any allocations will actually go there.

现在,malloc放置在area part_of_heap-part_of_heap+nbytes中的任何东西都将进入您自己的映射区域。但这是不受支持的,也不能保证任何资金分配都能实现。

Otherwise you would need to implement your own memory allocator, which has to do bookkeeping. A linked list would do for starters. I know of no open implementation that would serve your needs.

否则,您将需要实现自己的内存分配器,它必须进行簿记。一个链表可以作为开始。我知道没有任何开放的实现可以满足您的需要。