【问题标题】:How can I determine appropriate stack and heap sizes for ARM Cortex, using C++如何使用 C++ 确定 ARM Cortex 的适当堆栈和堆大小
【发布时间】:2011-07-13 19:53:38
【问题描述】:

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

【问题讨论】:

  • 这更多的是编译器和运行时库的特定性,而不是特定的 CPU 架构。但最重要的是,决定内存使用的是您的代码。使用 MMU 或数据断点来捕获堆栈溢出。
  • @Ben:Cortex-M3 没有 MMU,但它确实支持数据访问硬件断点,这可能有助于测试,但不适用于部署。
  • @Michael:鉴于 Clifford 答案的工具链特定组件,我不认为这在功能上是重复的。不过,这是一个有用的指针。

标签: c++ embedded arm cortex-m3


【解决方案1】:

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

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

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

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

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

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

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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      • 这确实是大多数堆栈大小的确定方式,这让我们的行业感到尴尬!
      【解决方案4】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-03-01
        • 2017-06-23
        • 1970-01-01
        • 2015-07-09
        • 1970-01-01
        • 2012-09-09
        • 2015-07-05
        • 2010-09-28
        相关资源
        最近更新 更多