Gcc 静态分配程序编译时间长
如果有人能告诉我为什么要编译这个程序,我将不胜感激:Gcc 静态分配程序编译时间长,gcc,Gcc,如果有人能告诉我为什么要编译这个程序,我将不胜感激: double data[123456789]; int main() {} 所需时间是编译此文件所需时间的10倍: int main() { double* data=new double[123456789]; } 当两者都使用以下工具编译时: $ g++ -O0 可执行文件的大小几乎相同 我在Ubuntu 10.04上使用GCC4.4.3 谢谢。动态分配 第二个程序在运行时分配内存;从编译器的角度来看,编译以下各项之间没
double data[123456789];
int main() {}
所需时间是编译此文件所需时间的10倍:
int main() {
double* data=new double[123456789];
}
当两者都使用以下工具编译时:
$ g++ -O0
可执行文件的大小几乎相同
我在Ubuntu 10.04上使用GCC4.4.3
谢谢。动态分配 第二个程序在运行时分配内存;从编译器的角度来看,编译以下各项之间没有真正的区别:
double *data = new double[123456789];
double *data = malloc(123456789);
double data = sqrt(123456789);
它们都做不同的事情,但编译器需要做的只是生成一个带有固定参数的外部函数调用。如果使用g++-S
生成程序集,则可以看到:
.text
main:
subq $8, %rsp /* Allocate stack space. */
movl $987654312, %edi /* Load value "123456789 * 8" as argument. */
call _Znam /* Call the allocation function. */
xorl %eax, %eax /* Return 0. */
addq $8, %rsp /* Deallocate stack space. */
ret
这对于生成任何编译器和链接器都很简单
静态分配
不过,正如您所注意到的,您的第一个程序有点捉弄人。如果我们看一下装配,我们会看到一些不同的情况:
.text
main:
xorl %eax, %eax /* Return 0. */
ret
.bss
data:
.zero 987654312 /* Reserve "123456789 * 8" bytes of space. */
当程序首次启动时,生成的程序集要求保留123456789*sizeof(double)
字节的空间。当这被组装并随后链接时(这发生在后台,即您只需运行g++foo.c
),链接器ld
将实际分配内存中的所有保留空间。这就是时间的方向。如果在运行g++
时运行top
,您将看到ld
占用了大量系统内存
减少了可执行文件的大小
一个合理的问题可能是“如果在链接时保留了内存,为什么我的可执行文件最终不是很大?”。答案隐藏在程序集中的.bss
标记中。这告诉链接器下面定义的数据不应该存储在最终的可执行文件中,而是在运行时分配给零
这就给我们留下了以下一系列步骤:
.bss
部分,并被标记为NOBITS
,这意味着数据仅为0,不需要物理地放入最终的可执行文件中。它避免了写出1GB的数据,而只是扔掉分配的内存- 链接器将需要使用与最终程序一样多的内存(外加一点)。如果您想静态分配4GB的RAM,您的链接器将需要4GB的RAM。这并不是链接器的工作方式,而是它们的实现方式
- 当分配大量内存时,动态地分配内存可以让您更好地处理错误(在屏幕上显示一条用户友好的消息,说明您没有足够的内存,而不是仅仅通过操作系统发送给用户的消息无法加载可执行文件)
- 动态分配内存允许您根据实际需要选择分配多少内存。(如果
是缓存,用户可以选择缓存大小,如果它存储中间结果,您可以根据问题调整大小,等等。)数据
- 动态分配内存允许您在以后释放内存,前提是您的程序需要继续运行,并在使用完内存后执行更多工作
最后,如果以上几点都不重要,并且您可以处理更长的编译时间,那么这可能不会太重要。静态分配内存可以简单得多,对于内存量较小的应用程序或一次性应用程序来说,这通常是正确的方法。非常有趣的观察结果。我注意到clang++(来自LLVM的2.8版本)具有完全相同的行为。我怀疑这段时间花在了链接器上,甚至是汇编程序上,而不是编译器上……一个快速测试证实了这段时间花在了链接器上(
g++-c-O0
对于这两个源几乎都是即时的)“链接器继续工作并分配这个内存”--这是LD中的一个bug,它已经被修复:GNU LD(适用于Ubuntu的GNU Binutils)2.22
显示了问题,而2.24.51.20131021
没有。