C/C++内存几大分区和存储空间的布局
先看一下可执行文件加载进内存后形成的进程在内存中的结构,如下图:

代码区:存放CPU执行的机器指令,代码区是可共享,并且是只读的。
数据区:存放已初始化的全局变量、静态变量(全局和局部)、常量数据。
BBS区:存放的是未初始化的全局变量和静态变量。
栈区:由编译器自动分配释放,存放函数的参数值、返回值和局部变量,在程序运行过程中实时分配和释放,栈区由操作系统自动管理,无须程序员手动管理。
堆区:堆是由malloc()函数分配的内存块,使用free()函数来释放内存,堆的申请释放工作由程序员控制,容易产生内存泄漏。
其中,BSS区由exec初始化为0,数据区和代码区由exec从程序文件中读入。
C语言中的存储类型有auto, extern, register, static 这四种,存储类型说明了该变量要在进程的哪一个段中分配内存空间,可以为变量分配内存存储空间的有数据区、BBS区、栈区、堆区。
1.auto
auto只能用来标识局部变量的存储类型,对于局部变量,auto是默认的存储类型,不需要显示的指定。因此,auto标识的变量存储在栈区中。
2.extern
extern用来声明在当前文件中引用在当前项目中的其它文件中定义的全局变量。如果全局变量未被初始化,那么将被存在BBS区中,且在编译时,自动将其值赋值为0;如果已经被初始化,那么就被存在数据区中。全局变量的生命周期是整个程序运行过程,为了节省内存空间,在当前文件中使用extern来声明其它文件中定义的全局变量时,就不会再为其分配内存空间。
3.register
声明为register的变量在由内存调入到CPU寄存器后,则常驻在CPU的寄存器中,因此访问register变量将在很大程度上提高效率,因为省去了变量由内存调入到寄存器过程中的好几个指令周期。
4.static
被static声明为静态类型的变量,无论是全局的还是局部的,都存储在数据区中,其生命周期为整个程序,如果是静态局部变量,其作用域为一对{}内,如果是静态全局变量,其作用域为当前文件。静态变量如果没有被初始化,则自动初始化为0。静态变量只能够初始化一次。
5.字符串常量
字符串常量存储在数据区中,其生存期为整个程序运行时间,但作用域为当前文件。
参考下图:

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1. C程序的存储空间布局:
C 程序由下面几个部分组成:
- 正文段(即是代码段): 这是由CPU执行的机器指令部分。通常,正文段是可以共享的,并常常是可读的,以防止程序因为意外原因而修改自身的代码!
- 初始化数据段(即数据段): 它包含了程序中需要明确的赋初值的变量。
- 非初始化数据段(bss段):在程序开始执行之前,内核将此段中的数据初始化为0或空指针。
- 栈。自动变量以及每次函数调用时所需保存的信息都存放在此段中。每次调用函数时,返回地址以及调用者的环境信息(如某些寄存器的值)都存放在栈中。然后,最近被调用的函数在栈上为其自动和临时变量分配存储空间。这样可以实现函数的递归调用!
- 堆。通常在堆中进行动态存储分配!
我们现在来做个实验来验证上述说法是否正确:
我们现在来编写一个Base程序,这个程序的main函数中没有自动变量,main函数的外部也没有非初始化数据;
2
3 int main(void)
4 {
5 return 0;
6 }
我们编译上述程序的到Base的可执行程序,然后用size命令观察各个程序段的大小:
text data bss dec hex filename
1115 552 8 1675 68b Base
下面我们在Base程序的main函数中增加一些初始化的变量:
2 int arr[1000] = {1};
3 int main(void)
4 {
7 return 0;
8 }
1115 4568 8 5691 163bDerive1
可见在mian函数之外增加了int arr[1000] = {1}; 语句之后data段增加4016byte!
2
3 int arr[1000];
4
5 int main(void)
6 {
7 return 0;
8 }
结果是:
1115 552 4032 5699 1643 Derive1
bss段增加了4024!
2. 存储器的分配:
函数原型:
malloc, free, calloc, realloc - allocate and free dynamic memory
SYNOPSIS
#include <stdlib.h>
void *malloc(size_t size);
void free(void *ptr);
void *calloc(size_t nmemb, size_t size);
void *realloc(void *ptr, size_t size);
函数说明:
ized(malloc分配出来的空间并未被初始化). If size is 0, then malloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().
The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to mal‐
loc(), calloc() or realloc().(free函数只能释放动态分配的空间) Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. If ptr is NULL, no operation is performed.
The calloc() function allocates memory for an array of nmemb elements of size bytes each and returns a pointer to the
allocated memory. The memory is set to zero.(callo函数分配出来的空间会被初始化) If nmemb or size is 0, then calloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().
The realloc() function changes the size of the memory block pointed to by ptr to size bytes. The contents will be
unchanged in the range from the start of the region up to the minimum of the old and new sizes. If the new size is
larger than the old size, the added memory will not be initialized. If ptr is NULL, then the call is equivalent to
malloc(size), for all values of size; if size is equal to zero, and ptr is not NULL, then the call is equivalent to
free(ptr). Unless ptr is NULL, it must have been returned by an earlier call to malloc(), calloc() or realloc(). If
the area pointed to was moved, a free(ptr) is done.


浙公网安备 33010602011771号