如何在嵌入式系统软件中优化或减小RAM大小?

时间:2011-04-16 09:00:41

标签: embedded

我正致力于汽车领域的嵌入式软件项目。在我的一个项目中,应用软件占用了近99%的RAM内存。可用的实际RAM大小为12KB。我们使用TMS470R1B1 Titan F05微控制器。我做了一些优化,比如在软件中查找未使用的消息并删除它们,但它仍然不值得减少RAM。你能否通过一些软件优化建议一些减少RAM的好方法?

6 个答案:

答案 0 :(得分:21)

与速度优化不同,RAM优化可能需要通过代码“在这里稍微有点”。另一方面,可能会出现一些“低悬的果实”。

数组和查找表

阵列和查找表可以是很好的“低悬的果实”。如果您可以从链接器获取内存映射,请检查RAM中的大型项目。

检查没有正确使用const声明的查找表,将它们放在RAM中而不是ROM中。特别要注意指针的查找表,它需要const正确的*,或者可能需要两个 const声明。 E.g:

const my_struct_t * param_lookup[] = {...};  // Table is in RAM!
my_struct_t * const param_lookup[] = {...};  // In ROM
const char * const strings[] = {...};    // Two const may be needed; also in ROM

堆栈和堆

也许您的链接器配置为堆和堆栈保留了大量的RAM,大于应用程序所需的RAM。

如果你不使用堆,你可以消除它。

如果您测量堆栈使用情况并且分配不佳,则可以减少分配。对于ARM处理器,对于多种操作模式,可能有多个堆栈,您可能会发现为异常或中断操作模式分配的堆栈大于所需的堆栈。

其他

如果您已经检查过轻松节省,并且仍然需要更多,您可能需要查看代码并保存“这里有点,有一点”。您可以查看以下内容:

全局与局部变量

检查static或全局变量的不必要使用,其中可以使用局部变量(在堆栈上)。我已经看到在函数中需要一个小的临时数组的代码,它被声明为static,显然是因为“它需要太多的堆栈空间”。如果在代码中发生这种情况足够多次,它实际上会节省总体内存使用量,以使这些变量再次本地化。它可能需要增加堆栈大小,但会在减少的全局/静态变量上保存更多内存。 (作为附带好处,函数更可能是可重入的,线程安全的。)

较小的变量

可以更小的变量,例如int16_tshort)或int8_tchar)代替int32_tint)。

枚举可变大小

enum可变大小可能比必要大。我不记得ARM编译器通常会做什么,但是我过去默认使用的一些编译器使enum变量为2个字节,即使enum定义实际上只需要1个字节来存储其范围。检查编译器设置。

算法实现

重做你的算法。一些算法具有一系列可能的实现,具有速度/存储器权衡。例如。 AES加密可以使用动态密钥计算,这意味着您不必将整个扩展密钥存储在内存中。这样可以节省内存,但速度较慢。

答案 1 :(得分:6)

删除未使用的字符串文字对RAM使用没有任何影响,因为它们不存储在RAM中而是存储在ROM中。代码也是如此。

您需要做的是减少实际变量以及堆栈/堆栈的大小。我会寻找可以调整大小和未使用的变量的数组。此外,由于memory fragmentation的危险,最好避免动态分配。

除此之外,您还需要确保查找表等常量数据存储在ROM中。通常可以使用const关键字来实现此目的。

答案 2 :(得分:5)

确保链接器生成MAP文件 - 它将显示RAM的使用位置。有时你可以找到保存在RAM中的字符串文字/常量之类的东西。有时您会发现其他人放置了未使用的数组/变量。

如果你有链接器映射文件,那么攻击首先使用最多RAM的模块也很容易。

答案 3 :(得分:3)

以下是我在Cell上使用的技巧:

  • 从显而易见的开始:尽可能将32位字压缩为16位,重新排列结构以消除填充,减少任何阵列中的松弛。如果你有超过8个结构的阵列,那么使用位域将它们打包得更加紧密是值得的。
  • 取消动态内存分配并使用静态池。恒定的内存占用更容易优化,并且您将确保没有泄漏。
  • 严格限制本地分配,以便它们不会长时间停留在堆栈上。有些编译器在识别变量完成时非常糟糕,并且会在函数返回之前将其保留在堆栈中。对于外部函数中的大对象来说,这可能会很糟糕,因为外部函数会更深入地调用树,因此会占用持久性内存,而不需要这些内容。
  • alloca()在函数返回之前不会清理,因此浪费的堆栈会比预期的更长。
  • 在编译器中启用函数体和常量合并,这样如果它看到具有相同值的八个不同的consts,它将只在文本段中放置一个并使用链接器对它们进行别名。
  • 优化可执行代码的大小。如果你有一个艰难的实时截止日期,你就知道你的代码需要多快运行,所以如果你有任何备用性能,你可以进行速度/大小权衡,直到你达到这一点。滚动循环,将常用代码拉入函数等等。在某些情况下,如果prolog / epilog开销大于函数体,则实际上可以通过内联某些函数来获得空间改进

最后一个仅与在RAM中存储代码的体系结构相关,我想。

答案 4 :(得分:3)

w.r.t函数,以下是优化RAM的句柄

  1. 确保深入分析传递给函数的参数数量。在根据AAPCS(ARM arch过程调用标准)的ARM体系结构中,最多可以使用寄存器传递4个参数,其余参数将被推入堆栈。

  2. 还要考虑使用全局而不是将数据传递给最常使用相同参数调用的函数的情况。

  3. 函数调用的越深,堆栈的使用就越重。使用任何静态分析工具,以了解最差的演员函数调用路径,并寻找场地来减少它。当函数A调用函数B时,B调用C,然后调用C,然后调用D,然后调用E并进入更深的位置。在这种情况下,寄存器不能在所有级别传递参数,因此显然会使用堆栈。

  4. 在适用的情况下,尝试将两个参数分成两个参数。请记住,ARM中的所有寄存器都是32位,因此进一步优化也是可能的。 void abc(bool a,bool b,uint16_t c,uint32_t d,uint8_t e)//利用寄存器和堆栈 void abc(uint8 ab,uint16_t c,uint32_t d,uint8_t e)//前2个参数可以被瞄准。所以可以使用寄存器

  5. 传递总共4个参数
  6. 重新审视嵌套中断向量。在任何架构中,我们都使用暂存寄存器和保留寄存器。保留寄存器是在服务中断之前需要保存的。在嵌套中断的情况下,需要巨大的堆栈空间来备份保留的寄存器到堆栈中。

  7. 如果结构类型的对象按值传递给函数,那么它会推送大量数据(取决于结构大小),这将容易占用堆栈空间。可以将其更改为通过引用传递。

  8. 问候

    barani kumar venkatesan

答案 5 :(得分:0)

添加到之前的答案。

如果从RAM运行程序以加快执行速度,则可以创建一个用户定义的部分,其中包含所有初始化例程,您确定它在系统启动后不会运行多次。执行完所有初始化函数后,您可以重新使用该区域进行堆。

这可以应用于在程序中某个阶段后被识别为无用的数据部分。