我的编程在C RAM有限的嵌入控制器与实时操作系统.

我定期打破我的代码短的功能,而每一功能的调需要更多的堆的记忆。每项任务需要他堆,这是一个显着记忆消费者的项目。

是否有替代保留的代码以及有组织的和可读的,仍然保留记忆?

有帮助吗?

解决方案

尝试使调用堆栈更平坦,而不是 a()调用 b()调用 c()调用< code> d(),有 a()调用 b() c() d( )本身。

如果函数只被引用一次,请将其标记为 inline (假设您的编译器支持此功能)。

其他提示

有3个组成部分给你堆的使用情况:

  • 呼叫功能返回的地址
  • 呼叫功能参数
  • 自动(当地的)变量

关键要最小化你的堆使用的是最大限度地减少参数通过,并自动变量。空间消耗的实际功能的电话本身是相当极小。

参数

一种方式来解决的参数问题是通过一个结构(通过的指针),而不是一个大数量的参数。


foo(int a, int b, int c, int d)
{
...
   bar(int a, int b);
}

这样做,而不是:


struct my_params {
   int a;
   int b;
   int c;
   int d;
};
foo(struct my_params* p)
{
   ...
   bar(p);
};

这种战略是良好的如果你通过了很多的参数。如果参数都是不同的,那么它可能会不为你工作.你最终会有一大的结构正在通过包含许多不同的参数。

自动变量(当地)

这往往是最大的消费者的堆空间。

  • 阵列是凶手。不要定义阵列在当地的功能!
  • 减少数的地方的变量。
  • 使用最小型的必要。
  • 如果重新入不是一个问题,可以使用模块的静态变量。

请记住,如果你只是移动的所有地方的变量从当地范围到模块的范围,你没有保存任何空间。你交易叠空间进行数据分段的空间。

一些实时操作系统的支助线的当地储存、分配"全球"存储在一个线程的基础。这可能会让你有多个独立的全球变量在每个任务为基础,但这会使你的代码不作为直接。

如果您可以节省大量主内存但只有一小部分堆栈,我建议您评估静态分配。

在C中,在函数内声明的所有变量都是“自动管理”的。这意味着它们被分配到堆栈中。

将声明限定为“静态”将它们存储在主存储器而不是堆栈中。它们基本上表现得像全局变量,但仍然允许你避免过度使用全局变量带来的坏习惯。您可以将大型长寿命缓冲区/变量声明为静态来减少堆栈压力。

请注意,如果您的应用程序是多线程的或者使用递归,则这不能正常工作。

启用优化,特别是积极的内联。编译器应该能够内联方法来最小化调用。根据您使用的编译器和优化开关,将某些方法标记为 inline 可能会有所帮助(或者可能会被忽略)。

使用GCC,尝试添加“-finline-functions” (或-O3)标志,可能还有“ -finline限= N&QUOT;标志。

为了评估嵌入式设置中代码的堆栈要求,我在某处阅读的一个技巧是在开始时使用已知模式填充堆栈空间(十六进制中的DEAD是我最喜欢的)并让系统运行而

正常运行后,读取堆栈空间并查看在运行过程中有多少堆栈空间未被替换。设计以留下至少150%的数据,以便处理可能尚未行使的所有可能的代码路径。

你能用全局变量替换一些局部变量吗? 特别是阵列可能会堆积起来。

如果情况允许你在一些函数之间共享一些全局变量, 你有可能减少记忆足迹。

折衷成本增加了复杂性,并且功能之间产生不必要的副作用的风险与可能更小的内存占用量的风险更大。

您的职能有哪些变量? 我们谈论的是什么尺寸和限制?

根据您的编译器以及优化选项的积极程度,您将为每个函数调用设置堆栈使用情况。因此,首先,您可能需要限制函数调用的深度。 一些编译器确实使用跳转而不是分支来实现简单的功能,这将减少堆栈的使用。显然你可以通过使用汇编程序宏来跳转到函数而不是直接函数调用来做同样的事情。

正如其他答案中所提到的,内联是一种可用选项,尽管这样做的代价是更大的代码。

吃堆栈的另一个区域是本地参数。这个区域你有一些控制权。使用(文件级别)静态将避免以静态ram分配为代价的堆栈分配。全球同样。

在(真正的)极端情况下,您可以为使用固定数量的全局变量作为临时存储而不是堆栈中的本地变量的函数提出约定。棘手的一点就是确保不会同时调用任何使用相同全局变量的函数。 (因此惯例)

如果你需要开始保留堆栈空间,你应该得到更好的编译器或更多的内存。

您的软件通常会增长(新功能,......),因此如果您必须通过考虑如何保留堆栈空间来启动项目,那么它从一开始就注定要失败。

是的,RTOS可以真正占用RAM用于任务堆栈使用。我的经验是,作为RTOS的新用户,有使用更多任务的倾向。

对于使用RTOS的嵌入式系统,RAM可以是一种宝贵的商品。为了保留RAM,对于简单的功能,在一个任务中实现多个功能仍然是有效的,这些功能以循环方式运行,具有协作式多任务设计。从而减少任务总数。

我想你可能在想象一个在这里不存在的问题。当大多数编译器“分配”时,它们实际上并没有做任何事情。堆栈上的自动变量。

在“main()”之前分配堆栈。被执行。当您从函数a()调用函数b()时,紧接在a使用的最后一个变量之后的存储区域的地址被传递给b()。如果b()然后调用函数c()然后c的堆栈在b()定义的最后一个自动变量之后开始,这将成为b()的堆栈的开始。

请注意,堆栈内存已经存在并已分配,没有进行初始化,所涉及的唯一处理是传递堆栈指针。

这成为问题的唯一时间是所有三个函数都使用大量存储,然后堆栈必须占用所有三个函数的内存。尝试保留在调用堆栈底部分配大量存储的函数,即不要从它们调用另一个函数。

内存存储系统的另一个技巧是将函数的内存占用部分拆分为单独的自包含函数。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top