C编译器是否在运行程序之前分配了所有必需的内存,还是为最大的内存块分配了内存? 在这两种情况下,我都在询问静态分配的内存,我了解动态内存分配是在运行时请求内存。
请参见下面的代码
#include <stdio.h>
int global_flag = 1; //using 4 bytes
void create_8_bytes()
{
/*
* create 2 integers , total 8 bytes
*/
int a = 3;
int b = 6;
}
void create_4_bytes()
{
/*
* 1 variable , total 4 bytes
*/
int a = 1;
}
void main()
{
create_8_bytes(); //8 bytes
create_4_bytes(); //4 bytes
puts("done");
}
运行上述程序需要多少内存?
答案 0 :(得分:4)
在非平凡的C / C ++程序中,通常无法预先知道运行时需要多少内存。这意味着,即使您的编译器尽了最大的努力,也无法始终生成静态地仅保留适当数量的内存的程序。
现代平台通常在某种程度上区分三种“类型”的内存:
malloc
等在运行时请求的内存您的程序所需的静态内存量无法轻松估算,因为它取决于操作系统,编译器,标准库等,因此变化很大。但是,您的程序非常小,因此可以令人惊讶的是,如果在任何平台上都需要超过几千字节的数据。在内存特别宝贵的平台上,可能只有几个字节。
您的程序不使用malloc
或其他分配函数,因此它不需要此类内存。
堆栈存储器是魔术发生的地方。堆栈是调用函数时程序可以使用(和重复使用)的内存区域。它的大小取决于平台(通常记录在某处),并且操作系统通常会优化其使用,以使程序在实际尝试使用内存之前不将其提供给程序。
如果堆栈内存不足,则会发生未定义的行为。在内存很宝贵的平台上,您可能会破坏程序的其他部分。如今,在大多数现代平台上,您都会崩溃。
假设您的程序没有经过优化,并且掩盖了一些平台细节,那么内存使用将看起来像这样:
main
:设置堆栈帧(约16个字节的整理信息)
create_8_bytes
:设置堆栈帧(约16个字节的内务处理,8个字节的变量)
create_8_bytes
:释放create_8_bytes
使用的堆栈框架
create_4_bytes
:设置堆栈帧(约16个字节的内务处理,4个字节的变量)
create_4_bytes
:释放堆栈框架
puts
(使用未知的内存量)
puts
main
如您所见,您使用的内存量随着输入和离开函数的增加而缩小。
尽管这为如何使用堆栈内存提供了正确的直觉,但请记住,如果编译器可以证明不会改变结果,则通常可以删除程序的某些部分。这意味着如果您不使用局部变量,您可能会希望它们消失,即使您确实使用了局部变量,编译器也可能会使用其他转换,从而使这些变量完全不使用堆栈内存。编译器还可能将堆栈内存用于您未明确告知它的事情。
答案 1 :(得分:2)
取决于编译器,您的环境,操作系统以及其他因素。无论如何,总会有一个开销要大于几个字节。
此外,该程序的大部分可能已被优化,因此那些ints
可能无关紧要。该程序只能简化为puts("done");
。
那些ints
将在堆栈中。因此create_8_bytes
将导致创建一个新的堆栈框架,该堆栈框架具有两个int的空间(还有更多空间,例如堆栈指针,因此,数字将关闭)。然后,完成create_8_bytes
后,其堆栈帧将无效,然后调用create_4_bytes
,这将使堆栈帧保存该int
。当然,所有情况都假定没有内联或优化的内容。
您可能想知道,a
中的b
和create_8_bytes
和a
中的create_4_bytes
是否会同时存在。他们不会。当然,实际的内存消耗并不代表函数调用的开销,程序本身(包括在puts
后面加载必要的代码)以及操作系统如何处理内存分配的总和会更多。与那十二个字节有关。而且,如果您要编译调试版本,那么所有这些都将再次大不相同,因为编译器不会优化原本会优化的东西,而会在程序中包含原本不会的东西,甚至可能提供了一个沙盒环境来运行您的程序,即使是最简单的应用程序也要占用数兆字节。