在堆上分配vs在递归函数中在堆栈上分配

时间:2015-10-02 14:43:07

标签: c++ c recursion memory-management embedded

当我定义一个递归函数时,在堆上分配局部变量然后在函数返回之前清理它们比在堆栈上分配它们更好/更安全。嵌入式系统上的堆栈大小非常有限,当递归运行得太深时,存在堆栈溢出的危险。

3 个答案:

答案 0 :(得分:5)

答案取决于您的应用程序域和平台的细节。 "嵌入式系统"是一个模糊的术语。 big oscilloscope running MS Windows or Linux位于频谱的一端。其中大部分都可以像普通PC一样进行编程。他们不应该失败,但如果他们这样做,只需重新启动它们。

另一方面是安全关键领域的控制器。考虑these Siemens switches,它必须在几毫秒内在所有情况下做出反应。失败不是一种选择。他们可能不运行Windows。可用资源有限。编程规则和程序在这里有很大不同。

现在让我们通过动态或自动内存分配来检查您拥有的选项,递归(或不是!)。

性能方面,堆栈速度更快,因此更受青睐。动态分配还涉及一些用于簿记的内存开销,如果数据单元很小则这是很大的。并且可能存在内存碎片问题,而自动内存不会发生(尽管导致碎片的场景 - 对象的不同生命周期 - 如果没有动态分配,可能无法直接解决)。

但确实在某些系统上,堆栈大小(大大小)比堆大小小;您必须阅读有关系统内存布局的信息。示波器将拥有大量内存和大堆栈;电源开关不会。

如果您担心内存不足,我会遵循Christian的建议,完全避免递归,而是使用循环。迭代可能会使内存使用率保持不变。此外,递归总是使用堆栈空间,例如返回地址和 - 值。分配"本地"的想法动态变量只对较大的数据结构有意义,因为你仍然必须将数据指针作为自动变量保存,这会占用堆栈空间(并且会增加整体内存占用量)。

通常,在资源有限的系统上,限制程序的最大资源使用非常重要。时间也是一种资源;动态分配使实时几乎不可能。

应用程序域规定了安全要求。在安全关键领域(起搏器!),程序一定不会失败。除非该计划是微不足道的,否则这个理想是不可能实现的,但是要做出很大的努力才能接近。在其他字段中,程序可能会在无法处理的情况下以定义的方式失败,但它不能以静默方式或以未定义的方式失败(例如,通过覆盖数据)。例如,不是动态分配未知数量的数据,而是只有一个预定义的数据固定大小的数组,而是使用数组中的元素,而不是绑定检查。

答案 1 :(得分:0)

  

当我定义一个递归函数时,在堆上分配局部变量然后在函数返回之前清理它们比在堆栈上分配它们更好/更安全。

你有C和C ++标签。这对两者都是一个有效的问题,但我只能评论C ++。

在C ++中,尽管效率稍差,但最好还是使用堆。如果你的堆内存不足,那可能会导致new失败。如果失败,new将抛出异常。但是,用尽堆栈空间不会导致异常,其原因之一是alloca is frowned upon in C++

答案 2 :(得分:0)

我认为一般来说,你应该完全避免在嵌入式系统中递归,因为每次调用函数时,返回地址都会被推送到堆栈。这可能会导致意外溢出。尝试切换到循环。

回到你的问题,mallocing会更慢但更安全。如果没有堆空间,则malloc将返回错误,您可以安全地清理内存。由于malloc可能非常慢,因此速度成本很高。

如果你知道你预期会有多少次迭代,你可以选择mallocing你需要的变量数组。这样你只需要malloc一次,这样可以节省时间,并且不会意外地填满堆或堆栈。此外,您只剩下一个变量可供免费使用。