Debugging 如何可视化AVR程序的内存(SRAM)使用情况?

Debugging 如何可视化AVR程序的内存(SRAM)使用情况?,debugging,memory,embedded,avr,avr-gcc,Debugging,Memory,Embedded,Avr,Avr Gcc,我在AVR微控制器(ATMega328P)上运行的C程序中遇到了一个问题。我相信这是由于堆栈/堆冲突造成的,但我希望能够确认这一点 是否有任何方法可以通过堆栈和堆来可视化SRAM的使用情况 注意:该程序使用avr gcc编译,并使用avr libc 更新:我遇到的实际问题是malloc实现失败(返回NULL)。所有mallocing都发生在启动时,而所有freeing都发生在应用程序的末尾(实际上,这永远不会发生,因为应用程序的主要部分处于无限循环中)。所以我确信碎片不是问题所在。通常的方法是用

我在AVR微控制器(ATMega328P)上运行的C程序中遇到了一个问题。我相信这是由于堆栈/堆冲突造成的,但我希望能够确认这一点

是否有任何方法可以通过堆栈和堆来可视化SRAM的使用情况

注意:该程序使用avr gcc编译,并使用avr libc


更新:我遇到的实际问题是malloc实现失败(返回
NULL
)。所有
malloc
ing都发生在启动时,而所有
free
ing都发生在应用程序的末尾(实际上,这永远不会发生,因为应用程序的主要部分处于无限循环中)。所以我确信碎片不是问题所在。

通常的方法是用已知的模式填充内存,然后检查哪些区域被覆盖。

如果同时使用堆栈和堆,那么可能会有点棘手。我将解释在不使用堆的情况下我做了什么。一般来说,我工作过的所有公司(在嵌入式C软件领域)都避免在小型嵌入式项目中使用堆,以避免堆内存可用性的不确定性。我们使用静态声明的变量

一种方法是在启动时用已知模式(例如0x55)填充大部分堆栈区域。这通常是在软件执行的早期由一小段代码完成的,要么就在main()的开始,要么甚至在启动代码的main()开始之前。当然,注意不要在此时覆盖正在使用的少量堆栈。然后,在运行软件一段时间后,检查堆栈空间的内容,并查看0x55在何处仍然完好无损。如何“检查”取决于目标硬件。假设您连接了一个调试器,那么您可以简单地停止微运行并读取内存

如果您有一个调试器可以执行内存访问断点(比通常的执行断点更奇特),那么您可以在特定堆栈位置(例如堆栈空间的最远限制)设置断点。这可能非常有用,因为它还可以准确地显示当达到堆栈使用程度时正在运行的代码位。但它需要调试器支持内存访问断点功能,而且在“低端”调试器中通常找不到


如果您也在使用堆,那么它可能会有点复杂,因为可能无法预测堆栈和堆将在何处发生冲突。

如果您可以编辑堆的代码,您可以在每个内存块上添加两个额外的字节(在资源如此低的情况下很棘手)。这些字节可能包含与堆栈不同的已知模式。如果它与堆栈发生冲突,则可以通过看到堆栈出现在堆栈内部或堆栈内部来提供线索。

假设您只使用一个堆栈(因此不是RTO或任何东西),并且堆栈位于内存末端,向下生长,而堆在BSS/数据区域之后开始生长。我见过malloc的实现,它们实际上检查stackpointer并在冲突时失败。你可以试着这么做

如果无法修改malloc代码,可以选择将堆栈放在内存的开头(使用链接器文件)。通常,知道/定义堆栈的最大大小总是一个好主意。如果你把它放在开头,你会在读RAM开头以外的内容时出错。堆将位于末尾,如果它是一个合适的实现,则可能无法增长到末尾之外(将返回NULL)。好消息是您知道,对于两个不同的问题,有两个不同的错误案例


要找出最大堆栈大小,可以使用一个模式填充内存,运行应用程序并查看它运行了多远,另请参阅Craig的回复。

不要在嵌入式目标上使用堆/动态分配。尤其是对于资源如此有限的处理器。而是重新设计应用程序,因为随着程序的增长,问题会再次出现。

在类似Unix的操作系统上,名为sbrk()的库函数(参数为0)允许您访问动态分配的堆内存的最高地址。返回值是void*指针,可以与任意堆栈分配变量的地址进行比较

使用该比较结果时应小心。根据CPU和系统架构的不同,堆栈可能从任意高地址向下增长,而分配的堆将从低绑定内存向上移动

有时,操作系统还有其他内存管理概念(即OS/9),它将堆和堆栈放在空闲内存的不同内存段中。在这些操作系统上,特别是对于嵌入式系统,您需要定义系统的最大内存需求
应用程序,使系统能够分配匹配大小的内存段。

您说malloc失败并返回NULL:

首先应该考虑的明显原因是堆“已满”——即,无法分配请求malloc的内存,因为它不可用

有两种情况需要记住:

答:你有一个16K的堆,你已经移动了10K,你试着再移动10K。你的堆实在太小了

b:更常见的情况是,你有一个16K的堆,你一直在做一系列malloc/free/realloc调用,而你的堆不到50%“满”:你调用malloc 1K,它失败了-怎么了?答-堆可用空间是碎片化的-没有连续1K的可用内存可以返回。当这种情况发生时,C堆管理器无法压缩堆,因此通常情况下是不好的。有一些技术可以避免碎片化,但很难知道这是否真的是问题所在。您需要将日志记录垫片添加到malloc和free中,这样您就可以得到一个想法
char *buffer;

void init()
{
  buffer = malloc(BUFFSIZE);
}
char buffer[BUFFSIZE];
AVR Memory Usage
----------------
Device: atmega16

Program:    7376 bytes (45.0% Full)
(.text + .data + .bootloader)

Data:         81 bytes (7.9% Full)
(.data + .bss + .noinit)

EEPROM:       63 bytes (12.3% Full)
(.eeprom) 
int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}
void setup () {
    Serial.begin(57600);
    Serial.println("\n[memCheck]");
    Serial.println(freeRam());
}