是否可以使用运算符new从堆以外的其他位置进行分配

Is it possible to use operator new to allocate from elsewhere than the heap?

本文关键字:其他 位置 分配 可以使 运算符 new 是否      更新时间:2023-10-16

这是我的应用程序的上下文:我正在开发一个使用不同设备的RAM的嵌入式系统。一部分在微控制器的内部RAM(128kB)中,另一部分是外部RAM(1MB)。这些存储器被映射到微控制器的地址空间中,但在非连续区域中。

内部RAM用于系统堆栈、任务堆栈和堆。外部RAM用于静态分配的数据(池、缓冲区和所有"static ..."内容)

我试图实现一个简单的内存管理结构,作为其中的一部分,我能够创建一个分配器,该分配器可以使用operator new的分配算法,但使用另一个内存源,而不是系统堆,而是其他地方的内存区域。你知道这是否可能吗?

一个使用的例子可以是保留100kB的外部RAM,并创建一个分配器来管理它,然后将它交给需要这个内存的指定任务。

static const uint8_t* ramBase = reinterpret_cast<uint8_t*>(0x80000000);
static const uint32_t ramAreaSize = 0x19000; //100kB
BufferAllocator allocator(ramBase, ramAreaSize);
//...
//Assuming operator new is overloaded to use BufferAllocator
MyObject * obj = new (allocator) MyObject(some, parameter);
//...

问题是:我如何(如果可能的话)实现BufferAllocator,以便使用operator new来管理原始内存区域?

void* BufferAllocator::allocate(uint32_t bytes)
{
    //I would like to write something like this
    //and so let the responsibility to manage this memory area to "new"
    //so I don't have to reimplement (or reuse) a different custom  
    // allocator
    return ::operator new(ramBase, ramAreaSize, bytes)
} 

我也面临着同样的问题,我能找到的唯一解决方案就是编写自己的mallocfree。我不需要任何特别的东西,所以我只是按照K&R的C编程语言(他们有一个简单的例子记录)。

然后我创建了两个堆:一个用于内部内存,另一个用于外部内存。我的堆栈在一个完全不同的内存块中(STM32F4上的CCRAM),所以我不需要担心sbrk。然而,我必须根据数据和bss段的大小知道内部SRAM堆的起始地址。这是根据链接器脚本注入的extern符号确定的。

我有足够的堆信息来了解它的当前大小、可用空间量以及是否有足够的连续内存来执行分配。如果内部SRAM内存不足,则尝试外部SRAM。如果内存不足,这与默认的malloc内存不足没有什么不同。

我使用的是GNU工具链,所以我可以使用--wrap选项来覆盖C标准库的默认mallocfreerealloccalloc(实际上是malloc_rfree_rrealloc_rcalloc_r,因为我使用的都是newlib)。由于newdelete最终打电话给malloc和朋友,我能够让它工作(至少满足我的需求)。

我对这种方法不是很有信心,但这是我在能力范围内能做的最好的事情。仔细考虑。

我很想知道一个更简单的解决方案。

没有向operator newmalloc()提供内存区域的标准方法。在类似POSIX的系统中,malloc()调用brk()sbrk(),可能还有mmap()来获取区域,因此您可以"捕获"这些调用并提供自己的实现,但这是不可移植的(这对mmap()来说是个问题)。

根据您的工具链,您可能能够向malloc()和/或operator new"解释"它应该在一些链接器脚本或类似的东西中处理两个或多个不同的内存区域。但这并不能保证。

除此之外,我能想到的唯一通用解决方案是在项目中使用不同的通用内存管理器(如jemalloc),并找到一种方法来为您的目的配置它。