我在静态内存分配和动态内存分配的文档中读到
静态内存分配是指在相关程序执行之前在编译时保留内存的过程,与在运行时进行的动态内存分配不同。
我的问题是:-
在编译期间如何保留内存?
举个例子
#include <stdlib.h>
void main()
{
int i;
}
上面的代码是一个例子static memory allocation
。
该变量i
仅在运行时(即程序执行期间)加载到内存中,那么在编译时如何为它分配内存?
我在静态内存分配和动态内存分配的文档中读到
静态内存分配是指在相关程序执行之前在编译时保留内存的过程,与在运行时进行的动态内存分配不同。
我的问题是:-
在编译期间如何保留内存?
举个例子
#include <stdlib.h>
void main()
{
int i;
}
上面的代码是一个例子static memory allocation
。
该变量i
仅在运行时(即程序执行期间)加载到内存中,那么在编译时如何为它分配内存?
将此程序编译为程序集时:
int i = 7;
int main()
{
return 0;
}
您可以看到全局变量i
位于“数据”部分,并且是静态分配的。
.globl _i
.data ## data section (for explicitly initialized global/static vars)
.align 2
_i: ## the global variable i
.long 7 ## is allocated here
.text
.globl _main
_main:
LFB0:
pushl %ebp
LCFI0:
movl %esp, %ebp
LCFI1:
movl $0, %eax
popl %ebp
LCFI2:
ret
LFE0:
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame1:
.set L$set$0,LECIE1-LSCIE1
.long L$set$0
LSCIE1:
.long 0
.byte 0x1
.ascii "zR\0"
.byte 0x1
.byte 0x7c
.byte 0x8
.byte 0x1
.byte 0x10
.byte 0xc
.byte 0x5
.byte 0x4
.byte 0x88
.byte 0x1
.align 2
LECIE1:
LSFDE1:
.set L$set$1,LEFDE1-LASFDE1
.long L$set$1
LASFDE1:
.long LASFDE1-EH_frame1
.long LFB0-.
.set L$set$2,LFE0-LFB0
.long L$set$2
.byte 0
.byte 0x4
.set L$set$3,LCFI0-LFB0
.long L$set$3
.byte 0xe
.byte 0x8
.byte 0x84
.byte 0x2
.byte 0x4
.set L$set$4,LCFI1-LCFI0
.long L$set$4
.byte 0xd
.byte 0x4
.byte 0x4
.set L$set$5,LCFI2-LCFI1
.long L$set$5
.byte 0xc4
.byte 0xc
.byte 0x5
.byte 0x4
.align 2
LEFDE1:
.subsections_via_symbols
C 中的对象可以具有以下三种存储期限之一:
具有静态存储时长的对象在程序启动时会为其分配内存,直到程序退出时才会释放内存。这通常是通过在程序映像本身中保留空间来完成的;IOW,您的程序的二进制文件有几个部分保留用于常量(.rdata
或.rodata
)和非常量(.bss
)数据。这就是他们在编译时保留的意思;编译器在生成的二进制文件中留出部分用于数据存储。但是,在程序加载到内存并运行之前,这些部分是不可用的。
具有自动存储持续时间的对象在程序进入其封闭范围时在运行时为它们分配内存,并在程序退出该范围时释放。
给定以下代码:
void foo( void )
{
int x;
for ( x = 0; x < 100; x++ )
{
int y = x * 2;
...
}
}
从逻辑上讲,for的空间x
会在进入函数的时候留出,foo
一直保持到foo
退出,而for的空间y
会在进入for
循环的时候留出,在循环退出的时候释放。在实践中(至少在我熟悉的平台上),两者的空间都将在函数进入时留出并在函数退出时释放,但你不应该假设空间y
在循环之外可以使用。
大多数系统使用堆栈来管理具有自动存储持续时间1的对象。
具有动态存储持续时间的对象通过调用库函数malloc
、calloc
或将其内存留出realloc
,并且该内存被保留,直到通过调用显式释放它free
:
void *foo( void )
{
void *mem = malloc( SOME_MEMORY );
...
return mem;
}
void bar( void )
{
void *data = foo();
...
free( data );
}
变量mem
和bar
都具有自动存储持续时间。mem
仅存在于 中foo
,数据仅存在于 中bar
。但是,它们都指向的对象具有动态存储持续时间;它被分配foo
并保留到bar
.
这些对象的内存池通常称为“堆”。
auto
变量行为的一种自然方式。然而,语言定义是以适应非基于堆栈的系统的方式编写的,尽管实现起来会很痛苦。
无论静态和动态内存分配如何,您的程序仅在执行时才获取内存。
执行时出现了静态和动态的概念。执行时静态内存分配在数据或代码段之一中。动态分配发生在您调用 malloc 或 calloc 在堆中获取内存时,这只发生在包含 malloc 或 calloc 的语句发生并且它们被称为动态时。
它不像编译后内存分配在你的 RAM 上。在 C 中,静态和动态概念仅在程序执行时出现,否则不会为您的代码分配内存。
编译代码时,编译器决定为每个对象(例如变量或函数代码)分配多少内存,它们将按什么顺序放置在内存中以及在什么地址。当然,在程序启动之前可能不会创建变量,但是预先分配了内存,变量地址已经编译到代码中 - 例如i
变量地址被编译到 i=7;
指令中。
编辑
变量可以静态或动态分配,动态变量可以自动分配(在 C/C++ 中,它们通常是函数中的局部变量,在堆栈或寄存器中创建)或“手动”,即以可控方式(由malloc
或new
并由free
或delete
) 处置。静态变量存在于整个过程生命周期,动态变量在需要时创建并在使用后销毁。
int fun( int param)
{
int automatic_var = 3;
return automatic_var + ++param;
}
int static_var = 7;
void main()
{
int automatic_var2;
automatic_var2 = fun( static_var);
}
在上面的代码中,automatic_var2
获取赋值11
。
变量存在static_var
于整个过程执行时间,
变量automatic_var2
存在于main()
执行时间,
变量automatic_var
只param
存在于fun()
执行时间。
有时,自动分配被认为是第三种方式,与自动的动态分配。无论如何,函数内部的声明,无论是否被认为是动态的int i;
,都肯定不是静态分配(即使是,其执行时间几乎main()
涵盖了整个进程的执行时间)。
在 C 中有四种存储形式:
一些作者将它们分为两类,静态和动态。每个人都同意静态是静态的,分配是动态的,但是您的示例是自动的,因此将其分配给其他类别之一是相当随意的。对我来说,只使用标准术语似乎更清楚。