我已经在上的AVR微控制器(ATMEGA328P)运行一个C程序中遇到的问题。我相信这是由于堆栈/堆碰撞,但我希望能够证实这一点。

是否有任何我可以由栈和堆可视化SRAM用法?

注意:程序编译与AVR-gcc和使用AVR-libc的

<强>更新我遇到的实际问题是,实施的malloc失败(返回NULL)。所有mallocing发生在启动和所有freeing发生在应用程序(实际上是永远不会因为应用程序的主要部分是一个无限循环)结束。所以我敢肯定不成不是问题。

有帮助吗?

解决方案

您说的malloc失败并返回NULL:

在明显的原因,你应该首先看的是你的堆是“全” - 即,你问的malloc内存无法分配,因为它是不可用的。

有两种情况要牢记:

答:你有一个16K的堆,你已经malloced 10 K和你尝试的malloc进一步10K。您的堆简直是太小了。

B:更常见的是,你有一个16k的堆,你已经做了一堆的malloc /自由/ realloc的调用和你堆不到50%“全”:你调用malloc为1K和失败 - 这是怎么回事?答 - 免费的堆空间是零散的 - 没有了可以返回空闲内存contigous 1K。 ç堆管理器无法压缩堆当这种情况发生,所以你一般是在一个糟糕的方式。有技术,以避免碎片,但它是很难知道这是真正问题所在。你需要记录垫片添加到malloc和free,这样你可以得到正在执行什么动态内存操作的想法。

编辑:

您说的所有mallocs发生在启动时,所以碎片不是问题。

在这种情况下,它应该是容易与静态更换动态分配。

旧代码示例:

char *buffer;

void init()
{
  buffer = malloc(BUFFSIZE);
}

新的代码:

char buffer[BUFFSIZE];

一旦你做到了这一点无处不在,你的连接器应该警告你,如果一切都无法适应的可用内存。不要忘记,以减少堆大小 - 但要注意某些运行时IO系统功能仍然可以使用堆,所以你可能无法完全删除

其他提示

您可以使用avr-size程序来检查RAM静态用法,如点击描述下 http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=62968 ,结果 http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=82536 ,结果 http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=95638 ,结果 和 http://letsmakerobots.com/node/27115

avr-size -C -x Filename.elf

(AVR-尺寸文档: http://ccrma.stanford.edu/planetccrma /man/man1/avr-size.1.html

如下如何设置这个上的IDE一个例子: 在代码:: Blocks的,项目 - >构建选项 - >前/后生成步骤 - >生成后的步骤,包括:

avr-size -C $(TARGET_OUTPUT_FILE) 或点击 avr-size -C --mcu=atmega328p $(TARGET_OUTPUT_FILE)

在构建结束输出示例:

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) 

数据是您的SRAM的使用,并且它仅仅是编译器的量 知道在编译时。您还需要空间,在创造的东西 运行时(特别是堆栈使用)。

要检查堆栈用法(动态RAM), 从 http://jeelabs.org/2011/05/22/atmega-memory-use/

下面是用于确定多少RAM如何是一个小工具功能 当前未使用的:

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());
}

在freeRam()函数返回的字节数的堆的端部和在堆栈上的最后一个分配的存储器之间如何存在,所以它实际上是多少堆叠/堆可以它们碰撞之前生长。

您可以检查周围代码此功能,你怀疑可能会导致栈/堆碰撞的回报。

通常的做法是用已知的图案来填充存储器,然后检查哪些区域被覆盖。

如果您同时使用栈和堆,那么它可以是一个小更棘手。我将解释在没有使用堆我做了什么。作为一般规则,所有我工作过的(在嵌入式C软件领域)的企业已经使用堆的小型嵌入式项目,以避免堆内存可用性的不确定性避免。我们用静态声明的变量来代替。

的一种方法是,以填补最堆栈区的与在启动时已知的图案(例如0x55的)。这通常是通过在软件执行初期的一小段代码完成,可以在开始右主(),或者甚至之前main()开始,在启动代码。小心不要覆盖在,当然这一点在使用堆栈的量小。然后,运行该软件一段时间后,检查的堆栈空间的内容,看看那里的0x55的仍然完好无损。你如何“考察”取决于你的目标硬件。假设你有连接的调试器,那么就可以简单地停止微运行和读取存储器。

如果你有一个调试器,可以做一个内存访问断点(有点比平常执行断点更看中的),那么您可以在一个特定的堆栈单元,如您的堆栈空间的最远极限设置一个断点。这是非常有用的,因为它也表明你到底是什么,当它达到堆栈使用的那种程度的码位运行。但是,它需要你的调试器,支持内存访问断点功能,它往往不是在“低端”调试器发现。

如果您还使用堆,那么它可以是一个比较复杂一点,因为它可能是不可能预测,其中堆栈和堆会发生碰撞。

不要使用嵌入式目标堆/动态分配。特别是与具有这种有限的资源的处理器。而是重新设计你的应用程序,因为这个问题将再次出现为你的程序的增长。

假设你仅使用一个叠层(因此不是RTOS或任何东西),并且堆栈在存储器结束时,生长了下来,而堆在BSS / DATA区域后开始,长大。我见过的malloc实现,真正把该stackpointer和失败上的碰撞。你可以尝试这样做。

如果你不能够适应malloc的代码,你可以选择把你的筹码在内存的开始(使用连接文件)。一般它总是知道/定义堆栈的最大尺寸是个好主意。如果你把它在一开始,你会阅读超出RAM的开始得到一个错误。该堆将在年底大概可以不可超出如果它是一个体面的implemantation结束(将返回NULL代替)。好东西是你知道有2个单独的错误的情况下为2点独立的问题。

要找出最大堆栈大小,你可以用图案填充你的内存,运行应用程序,看看它是如何走多远,又见从克雷格回答。

如果你能为你堆编辑代码,你可以用一对夫妇的每个内存块额外的字节(上如此低的资源棘手)填充它。这些字节可以包含从堆栈不同的已知图案。如果其看到它出现在堆栈或反之亦然内与堆栈碰撞这可能给你一个线索。

在类似Unix的操作系统库名为SBRK函数()为0的参数,可以访问动态分配的堆存储器的最顶部地址。返回值是一个void *指针,并且可以与任意的分配堆栈的变量的地址进行比较。

使用该比较的结果,应小心使用。根据CPU和系统体系结构,该堆栈可以是来自任意高地址向下生长而分配的堆将向上从低结合的存储器移动。

有时候操作系统具有用于存储器管理哪些地方堆,并在空闲存储器不同的存储器段堆叠其他概念(即OS / 9)。在这些操作系统上 - 尤其是对嵌入式系统 - 你需要定义的最大内存要求你  预先应用程序来支持系统分配匹配大小的内存段。

scroll top