如何使用C ++确定ARM Cortex的适当堆栈和堆大小

时间:2011-03-11 22:06:08

标签: c++ embedded arm cortex-m3

cortex M3处理器启动文件允许您指定专用于堆栈和堆的RAM量。对于c ++代码库,是否有一般的经验法则或者更明确的方法来确定堆栈和堆大小的值?例如,您是否会计算唯一对象的数量和大小,或者可能使用已编译的代码大小?

4 个答案:

答案 0 :(得分:16)

  

cortex M3处理器启动文件   允许您指定的数量   RAM专用于堆栈和   堆。

这不是Cortex-M3的功能,而是开发工具链提供的启动代码。这是Keil ARM-MDK M3默认启动文件的工作方式。这有点不寻常;更常见的是,您将指定堆栈大小,并且链接器和链接器的静态内存分配之后的任何剩余内存将成为堆;这可以说是更好的,因为你最终没有一堆无法使用的内存。您可以修改它并使用替代方案,但您需要知道自己在做什么。

如果 使用Keil ARM-MDK,则链接器选项--info = stack和--callgraph将信息添加到帮助堆栈需求分析的映射文件中。这些和其他技术被描述为here

如果您使用的是RTOS或多任务内核,则每个任务都有自己的堆栈。操作系统可能提供堆栈分析工具,Keil的RTX内核查看器显示当前堆栈使用情况,但不显示峰值堆栈使用情况(因此大多数情况下无用,并且只能用于具有默认堆栈长度的任务)。

如果你必须自己实现堆栈检查工具,通常的方法是用一个已知值填充堆栈,并从高地址开始,检查值,直到找到第一个不是填充字节的值,这将给出堆栈的高潮标记。您可以实现代码来执行此操作,也可以从调试器手动填充内存,然后在调试器内存窗口中监视堆栈使用情况。

堆需求将取决于代码的运行时行为;你必须自己分析一下,但是在ARM / Keil Realview中,当C ++的new引发异常时,将调用MemManage Exception处理程序;我不确定malloc()是否这样做或只是返回NULL。您可以在异常处理程序中放置断点或修改处理程序以发出错误消息以检测测试期间的堆耗尽。还有一个__heapstats()函数可用于输出堆信息。它有一个有点麻烦的界面,我把它包裹起来:

void heapinfo()
{
typedef int (*__heapprt)(void *, char const *, ...);
    __heapstats( (__heapprt)std::fprintf, stdout ) ;
}

答案 1 :(得分:3)

编译后的代码大小无济于事,因为代码不会在堆栈中运行,也不会在堆中运行。 Cortex-M3器件通常在具有内置闪存和相对少量RAM的微控制器上实现。在此配置中,代码通常从Flash运行。

堆用于动态内存分配。计算唯一对象的数量将为您提供粗略估计,但您还必须考虑使用动态内存分配的任何其他元素(使用C ++中的new关键字)。通常,在嵌入式系统中避免动态内存分配,原因很简单,堆大小难以管理。

在异常处理例程期间,堆栈将用于变量传递,局部变量和上下文保存。除非你的代码分配了一大块本地内存或一个大对象,否则通常很难对堆栈的使用有所了解。一种可能有用的技术是为堆栈分配所有可用的RAM。使用已知模式填充堆栈(0x00或0xff不是最佳选择,因为这些值经常发生),运行系统一段时间然后检查堆栈以查看使用了多少。不可否认,这不是一种非常精确或科学的方法,但在许多情况下仍然有用。

答案 2 :(得分:1)

最新版本的IAR编译器有一个功能,可根据代码的静态分析确定所需的堆栈大小(假设您没有任何递归)。

如果您没有确切的数字,一般的方法是尽可能大,然后当您开始耗尽内存时,开始修剪堆栈直到程序因堆栈结束而崩溃流。我希望这是一个笑话,但这就是通常的方式。

答案 3 :(得分:1)

减少直到它崩溃是一种快速的临时方式。您还可以使用已知值填充堆栈,例如0xCCCC,然后通过扫描0xCCCC来监控最大堆栈使用情况。 它不完美,但比寻找崩溃要好得多。

理由是,减少堆栈大小并不能保证堆栈溢出会使某些东西“可见”。