外部 RAM 中的动态矢量分配
Dynamic vector allocation in external RAM
我目前正在使用GCC进行C++STM32F7 cortex-m7微控制器的大型项目。我需要在外部 SDRAM (16 MB) 中存储一个宽数组,其中包含音符结构的向量(每个 12 字节)。我已经创建了一个有效的FMC和一个自定义RAM区域
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 512K
FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 1024K
SDRAM (xrw) : ORIGIN = 0xC0000000, LENGTH = 16M
}
/* Define output sections */
SECTIONS
{
/* Section créée pour l'allocation dans la SDRAM externe*/
.fmc :
{
. = ALIGN(8);
*(.fmc)
*(.fmc*)
. = ALIGN(8);
} >SDRAM
我的数组是这样声明的:
std::vector<SequencerNoteEvent> NotesVectorArray[kMaxPpqn] __attribute__((section(".fmc")));
到目前为止还好。我在外部RAM中创建了一个矢量数组。我怎样才能继续创建我的向量元素
NotesVectorArray[position].push_back(note);
动态地发生在同一个外部RAM中?我目前只能使用__attribute__(section)
声明静态数据
我读了很多关于C++分配器、内存池的东西,但我不明白分配在矢量代码中发生的位置以及我应该如何替换它......我"只是"需要拥有与平时相同的分配系统,但在我记忆的另一部分是这种精确的类型。
似乎可以有多个堆。分散文件和有效内存分配之间的连接在哪里?
提前感谢,
本
我遇到了同样的问题,并通过重新定义operator new
得到了一个可行的解决方案。与使用自定义分配器相比,这样做的好处是所有动态分配将自动在 SDRAM 中,因此您可以自由使用 std::function 或任何需要堆的 STL 容器,而不必每次都传递自定义分配器参数。
我做了以下工作:
-
通过将
-nostdlib
添加到编译标志来删除标准库。我还将其添加到链接器标志中。此外,从编译器和链接器标志中删除和--specs=...
。奖励:您将节省~60-80k的代码空间! -
编写自己的替换
operator new
,operator delete
。我创建了一个名为new.cpp
添加了以下内容的新文件:(取自 https://arobenko.gitbooks.io/bare_metal_cpp/content/compiler_output/dyn_mem.html)
//new.cpp
#include <cstdlib>
#include <new>
void *operator new(size_t size) noexcept { return malloc(size); }
void operator delete(void *p) noexcept { free(p); }
void *operator new[](size_t size) noexcept { return operator new(size); }
void operator delete[](void *p) noexcept { operator delete(p); }
void *operator new(size_t size, std::nothrow_t) noexcept { return operator new(size); }
void operator delete(void *p, std::nothrow_t) noexcept { operator delete(p); }
void *operator new[](size_t size, std::nothrow_t) noexcept { return operator new(size); }
void operator delete[](void *p, std::nothrow_t) noexcept { operator delete(p); }
- 在
- 链接器脚本中定义一个对应于最低 SDRAM 地址(堆的开始)的变量。这不是绝对必要的,因为您可以在步骤 4 中的代码中使用常量 (0xC0000000),但它使将 SDRAM 地址保存在一个位置变得更加容易。只需添加一行:
PROVIDE( _fmc_start = . );
//linker script
[snip]
/* Section créée pour l'allocation dans la SDRAM externe*/
.fmc :
{
. = ALIGN(8);
PROVIDE( _fmc_start = . );
*(.fmc)
*(.fmc*)
. = ALIGN(8);
} >SDRAM
new
的新实现将直接调用malloc()
,当堆中需要内存块时,它会调用_sbrk()
。 因此,您必须定义_sbrk()
来跟踪堆指针,并且只需在链接器脚本中刚刚定义的最低 SDRAM 地址处启动指针。 这是我所做的:
//sbrk.cpp, or append this to new.cpp
#include <cstdlib>
extern "C" size_t _sbrk(int incr)
{
extern char _fmc_start; // Defined by the linker
static char *heap_end;
char *prev_heap_end;
if (heap_end == 0)
heap_end = &_fmc_start;
prev_heap_end = heap_end;
//Optionally can check for out-of-memory error here
heap_end += incr;
return (size_t)prev_heap_end;
}
- 此时,如果您尝试编译,可能会收到许多链接器错误。确切的错误将取决于您的项目使用的标准库的哪些部分,而不仅仅是新建和删除。就我而言,我正在使用
std::function
,编译器抱怨它没有__throw_bad_function_call()
。您可能还会看到诸如_init()
和_fini()
和__errno
之类的错误。基本策略是为每个函数创建自己的空函数存根或变量声明。值得快速搜索一下其中的每一个,看看它们有什么用途,你可能会发现你的项目或你包含的库正在使用一些你不知道的功能!创建存根时,需要正确匹配函数签名,因此也需要搜索互联网。许多存根用于处理错误/异常,因此您可以决定如何在函数体中处理它(或忽略错误)。
例如,下面是有关(过时但必需的)_init()
和_fini()
函数的一些信息:https://tldp.org/HOWTO/Program-Library-HOWTO/miscellaneous.html
以下是有关__dso_handle
的一些信息: https://lists.debian.org/debian-gcc/2003/07/msg00057.html
__cxa_pure_virtual(): __cxa_pure_virtual的目的是什么?
以下是我的项目需要工作的内容:
//syscalls.cpp
extern "C" {
void _init(void) {}
void _fini(void) {}
int __errno;
void *__dso_handle = (void *)&__dso_handle;
}
namespace std
{
//These are error handlers. They could alternatively restart, or log an error
void __throw_bad_function_call() { while (1); }
void __cxa_pure_virtual() { while (1); }
} // namespace std
完成所有这些之后,它最终将编译,如果您使用调试器,您将看到向量的地址从0xC0000000
开始!
- 以下代码执行哪种内存分配(动态或静态)?
- 取消分配动态分配的字符数组的析构函数
- 如何正确分配动态创建int并将其分配给具有值的动态数组数组
- 当分配动态内存以存储字符串副本时,程序会中断
- 在 mmap 内存中高效分配动态数组
- C++分配 - 动态分配数组并从文件中读取记录 - 挂起
- 指针数组分配动态内存
- 模板c++来分配动态矩阵2D
- "Delete"不取消分配动态内存
- 解除分配动态内存
- 分配动态分配的指针数组
- 分配动态阵列C++期间的分段错误
- 如何在 c++ 中最好地分配动态内存
- 分配动态数组时,是否删除了前面的元素
- C++ 在函数内分配动态数组
- 如何在OpenMP C++中分配动态内存
- 将数组的所有点设置为0对重新分配动态内存有不同的影响
- 为什么我们不能在堆栈上分配动态内存?
- 使用向量构造函数来分配动态内存
- 为数组分配动态值