2010-11-10 55 views
3

我正在为c编写一个Atmel XMEGA微控制器的固件,我想我填充了4 KB的SRAM。据我所知,我只有静态/全局数据和本地堆栈变量(我在我的代码中使用malloc)。我如何知道我的记忆是否已满?

我使用本地变量缓冲一些像素数据。如果我将缓冲区增加到51字节,我的显示器显示出奇怪的结果 - 一个6字节的缓冲区运行良好。这就是为什么我认为我的内存已满并且堆栈覆盖了某些内容。

创建更多的空闲内存是而不是我的问题,因为我可以将一些静态数据移动到闪存中,只在需要时才加载它。令我困扰的是,我从未发现记忆已满。

当内存被填满而不是让它覆盖其他数据时,是否有可能发现(例如,通过重置微控制器)?

回答

3

要准确预测需要多少堆栈可能非常困难(如果打开正确的选项,某些工具链可能会遇到问题,但这只是一个粗略的指导)。

检查堆栈状态的常用方法是在启动时用完全已知的值填充堆栈,尽可能难以运行代码,然后查看未覆盖多少堆栈。

您的工具链的启动代码甚至可能会有一个选项为您填充堆栈。不幸的是,虽然这些概念非常简单:用已知的值填充堆栈,计算剩余的值的数量,但实现它的实际可能需要深入理解特定工具(特别是启动代码和链接器)工作。

粗略的方法来检查堆栈溢出是什么导致您的问题是使所有本地数组“静态”和/或大幅度增加堆栈的大小,然后看看事情是否更好。这些在小型嵌入式系统上都很难做到。

0

通常你的编程工具知道控制器的参数,所以如果你使用更多(没有mallocs,它在编译时已知)应该被警告。

但是你应该小心pixeldata,因为大多数显示器没有线性地址空间。

编辑:通常你可以手动指定堆栈大小。留下足够的内存用于静态变量,并保留其余的堆栈。

+0

据我所知,局部变量确实存在于堆栈中。但是堆栈的大小在编译时还不知道,还是我错了? – Martin 2010-11-10 09:41:52

+0

@Martin:如果你不使用递归和变量大小的局部变量(字母只允许一些C编译器),则可以在编译时知道栈的大小。 – Curd 2010-11-10 09:56:23

1

“是它在某种程度上可能dected(由正在重置微控制器例如 )时 内存得到了填补,而不是 让它覆盖其他一些数据?”

我想现在你有一个内存映射像(1)。 当堆栈和/或变量空间增长很多时,它们会相互冲突并相互覆盖(*)。

另一种可能性是类似于(2)的存储器映射。 当堆栈或变量空间超过最大空间时,它们会遇到未映射的addr空间(*)。 根据控制器(我不确定AVR家族),这会导致重置/陷阱或类似(=您所期望的)。

[not mapped addr space][ RAM mapped addr space ][not mapped addr space] 
(1)      [variables ---> * <--- stack] 
(2)      *[ <--- stack variables ---> ]* 

(箭头表示生长方向,如果使用更多的变量/堆栈)

当然最好是要确保事前即RAM足够大。

1

通常,链接器负责为代码,常量,静态数据,堆栈和堆分配内存。通常你必须指定所需的堆栈大小(和可用内存)给链接器,如果它不适合所有东西,它将会标记一个错误。

还要注意,如果你正在处理多线程应用程序,那么每个线程有它自己的堆栈,并且这些经常在线程启动时从堆中分配。

除非你的处理器有一些硬件检查堆栈溢出(不太可能),你可以使用一些技巧来监视堆栈的使用情况。

  • 用已知的标记模式填充堆栈,并检查堆栈内存(由链接器分配)以确定标记的多少未被破坏。
  • 在一个定时器中断(或类似)比较与所述堆叠的底部的主线程堆栈指针以检查溢出

这两种方法都在调试是有用的,但它们不能保证捕捉所有问题,并且通常只会在堆栈已经损坏其他东西之后标记问题...