【问题标题】:Is it possible to use operator new to allocate from elsewhere than the heap?是否可以使用 operator new 从堆以外的其他地方进行分配?
【发布时间】:2015-06-06 10:02:57
【问题描述】:

这是我的应用程序的上下文:我正在开发一个使用来自不同设备的 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)
} 

【问题讨论】:

  • 是的,这是可能的,这是正确的语法。不过,您不能只使用delete 来释放对象。另一种选择是重载 operator newoperator delete 只为您的 MyObject 类型,因此您不需要使用放置新语法。
  • 这个问题:stackoverflow.com/questions/7194127/… 是开始阅读的好地方。
  • 如果您要使用placement new,请使用-&gt;~() 进行删除。
  • 我只是发现我的问题不是很清楚,所以我对其进行了编辑以添加一些细节:问题不是关于重载 operator new 以使用自定义分配器进行分配,而是关于BufferAllocator 使用已经为 operator new 实现的内存管理
  • 基本上,您是在尝试在固定的内存区域上实现自己的堆。如果块分配器(所有块大小相同)可以 - 搜索它,这已经完成了很多次。

标签: c++ memory-management embedded


【解决方案1】:

我也遇到了同样的问题,我能找到的唯一解决方案是编写自己的 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 和朋友,我能够使它工作(至少满足我的需要)。

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

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

【讨论】:

  • 我想我会选择与您的解决方案类似的解决方案,因为它似乎无法做我想做的事......我正在使用 MDK ARM 工具链开发 Cortex-M3 (EFM32GG) .我认为-wrap 选项不是一个好的解决方案,因为预期的行为依赖于构建命令行,我打算将此代码编写为可在项目之间共享(它将成为框架的一部分)。这里有一些来自 ARM 的有趣链接,用于在运行时扩展堆:Extending heap size at runtime
【解决方案2】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-04
    • 1970-01-01
    • 2017-01-31
    • 1970-01-01
    相关资源
    最近更新 更多