由于变量更频繁地被解除分配,因此使较小的函数通常在内存方面更有效吗?

时间:2011-08-11 05:56:18

标签: c compiler-construction

将工作划分为5个函数而不是一个大函数C中的内存效率更高,因为在给定时间内存储器中的变量更少,因为堆栈帧更频繁地被解除分配?它取决于编译器和优化吗?如果是这样,编译器会更快吗?

答案给出了很多局部变量,堆栈框架来自集中式主要部分而不是彼此叠加。

我知道将函数分解为更小函数的其他优点。请回答这个问题,仅限于内存使用情况。

5 个答案:

答案 0 :(得分:2)

可能减少程序堆栈使用的“高水位线”,如果是这样,可能会降低程序的整体内存需求。

是的,这取决于优化。如果优化器内联函数调用,您可能会发现所有内联函数的所有变量都包含在一个大堆栈框架中。任何值得使用的编译器都能够内联[*],因此它可能发生的事实并不依赖于编译器。究竟什么时候发生,会有所不同。

如果你的局部变量很小,那么你的程序使用更多的堆栈比在启动时自动分配给你的堆栈要少得多。除非你已经超过了最初给出的内容,否则你使用多少对整体内存要求没有任何影响。

如果你在堆栈上放置了很大的结构(多个千字节),或者如果你在千兆字节的内存很多的机器上,那么它可能会对整体内存使用产生影响。所以,如果通过“很多局部变量”你的意思是几十个int和指针然后没有,你做的任何事情都没有任何显着差异。如果通过“很多局部变量”你的意思是几十个10k缓冲区,或者如果你的函数非常深入,那么你的几十个int就有数百个级别,那么它可能是最不可能的差异,取决于操作系统和配置。

堆栈和堆通过通用RAM相互增长的模型,中间的空闲内存可以被其中任何一个同等地使用,是过时的。除了极少数非常受限制的系统外,内存模型不再以这种方式设计。在现代操作系统中,我们有所谓的“虚拟内存”,并且堆栈空间一次分配给您的程序一页。它们中的大多数在使用时会自动分配更多页面的堆栈,最多可达到通常非常大的配置限制。一些不自动扩展堆栈(Symbian最后我使用它,这是几年前,没有,虽然可以说Symbian不是一个“现代”操作系统)。如果您使用的是嵌入式操作系统,请查看手册中有关堆栈的内容。

无论哪种方式,影响总内存使用的唯一因素是任何时候您需要多少页堆栈。如果您的系统自动扩展堆栈,您甚至不会注意到您使用了多少。如果没有,你需要确保程序有足够的堆栈用于其高水位标记,并且当你可能注意到过多的堆栈使用时。

简而言之,这是理论上有所作为的事情之一,但在实践中,差异几乎总是微不足道的。只有当你的程序相对于它运行的环境的资源使用大量的堆栈时才重要。

[*]使用基本上是非优化汇编程序的C编译器在C语言中编写PIC或其他东西的人员被允许冒犯我称其编译器“不值得使用”。这些设备上的堆栈与“典型”系统完全不同,无论如何答案都不同。

答案 1 :(得分:1)

我认为在大多数情况下,为堆栈分配的内存区域(整个程序)保持不变。使用中的 的数量将根据调用堆栈的深度而改变,当使用的变量较少时,该数量会减少(但请注意,函数调用也会推送返回地址和堆栈指针)。

它还取决于函数的调用方式。例如,如果两个函数串行调用,并且第一个的堆栈在调用第二个函数之前弹出,那么你将使用更少的堆栈..但如果第一个函数调用第二个函数那么你就是使用一个大函数(加上函数调用开销)回到原来的位置。

答案 2 :(得分:0)

是的,同样地,在喷气式飞机上使用更精细的涂料可以增加其空气动力学性能。好吧,这是一个很糟糕的比喻,但重点是,如果有一个问题要求清楚,电报或试图使用更多的功能,请使用电报。在大多数情况下,这些并不是相互排斥的,因为初学者倾向于提供太多的子程序或功能。

就记忆而言,我认为如果你真正分手工作(f,然后是g,那么h)那么你会看到一些可用的内存增加,但如果它们是相互依赖的那么你就不会。

正如@Joel Burget所说,内存管理并不是代码结构中的一个考虑因素。

我的看法。

答案 3 :(得分:0)

堆栈上没有内存分配 - 只是将堆栈指针移向下一个值。堆栈大小本身是预定义的。所以内存使用没有区别(当你得到堆栈溢出时的情况除外)。

答案 4 :(得分:0)

将一个巨大的功能拆分成较小的功能确实有其优点,其中包括可能更优化的内存使用。

说,你有这个功能。

void huge_func(int input) {
    char a[1024];
    char b[1024];
    // do something with input and a
    // do something with input and b
}

你将它分成两部分。

void func_a(int input) {
    char a[1024];
    // do something with input and a
}

void func_b(int input) {
    char b[1024];
    // do something with input and b
}

调用huge_func将占用至少2048字节的内存,调用func_a然后调用func_b可获得相同的结果,内存减少约一半。但是,如果在func_a内调用func_b,则使用的内存量与huge_func大致相同。基本上,正如@ sje397写的那样。

我说这个可能是错的,但我认为没有任何编译器优化可以帮助您减少堆栈内存的使用。我相信堆栈内存的布局必须确保为所有声明的变量保留足够的内存,无论是否使用。