每日一问11:C++程序的内存格局

每日一问11:C++程序的内存格局

  网上对于C++程序的内存格局有两种分法,这里两种分法都学习一下。

四分法

  四分法是更为常见的分法,其内存格局如下:

其中,

  1. 栈区,栈又称堆栈, 内存由编译器在需要时自动分配和释放。通常用来存储局部变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,栈用来传递参数和返回值。栈运算分配内置于处理器的指令集中,效率很高,但是分配的内存容量有限。(为运行函数而分配的局部变量、函数参数、返回地址等存放在栈区)。
  2. 堆区,堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc/free等函数分配内存时,新分配的内存就被动态添加到堆上 (堆被扩张)/释放的内存从堆中被剔除(堆被缩减)。
  3. 全局数据区,存放全局变量、静态数据和常量;(在程序编译时期分配好的,在程序的整个运行期间都存在)。
  4. 代码区,所有类成员函数和非成员函数代码存放在代码区。该区是只读的,任何尝试对该区的写操作会导致段违法出错。代码区是被多个运行该可执行文件的进程所共享的。

五分法

  这种分法来源于《C++内存管理技术内幕》一书,将C++中的内存分为了5个区,分别是:堆,栈,自由存储区,全局/静态存储区,常量存储区。 这种分法,没有提到代码区,将全局数据区细分为全局/静态存续区和常量存续区,将堆区分为堆和自由存储区。

  1. 栈区,同上。

  2. 堆区,内存使用new进行分配,使用delete或delete[]释放。如果未能对内存进行正确的释放,会造成内存泄漏。但在程序结束时,会由操作系统自动回收。

  3. 自由存储区:使用malloc进行分配,使用free进行回收。和堆类似。

  4. 全局/静态存储区:全局变量和静态变量被分配到同一块内存中,C语言中区分初始化和未初始化的,C++中不再区分了。

  5. 常量存储区:存储常量,不允许被修改。

更为完善的结构

​ 一个进程在内存中的布局:

​ 其中,BBS段含了程序中未初始化全局变量,在内存中bss段全部置零。

程序样例

//main.cpp 
static int s = 1;				//全局静态变量 (全局/静态存储区)
int a = 0; 						//全局初始化区(全局/静态存储区)
char *p1; 						//全局未初始化区 (BSS)
int main() 
{ 
	int b; 						//栈 
	char s[] = "abc"; 			//栈 
	char *p2; 					//栈 
	char *p3 = "123456"; 		//123456\0在常量区,p3在栈上。 
	static int c =0;			//局部静态变量  (全局/静态存储区)
	p1 = (char *)malloc(10); 	//分配得来得10和20字节的区域就在堆区。
	p2 = (char *)malloc(20); 
	strcpy(p1, "123456"); 		//123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
   	return 0;
}  

一些问题

  自由存储区和堆的区别:从技术上来说,堆(heap)是C语言和操作系统的术语,堆是操作系统所维护的一块特殊内存,它提供了动态分配的功能,使用malloc()、free()来申请/释放内存。而自由存储是C++中通过new和delete动态分配和释放对象的抽象概念。基本上,所有的C++编译器默认使用堆来实现自由存储。也就是说,默认的全局运算符new和delete也许会使用malloc和free的方式申请和释放存储空间,也就是说自由存储区就位于堆上。但程序员也可以通过重载操作符,改用其他内存来实现自由存储,例如全局变量做的对象池,这时自由存储区就不位于堆上了。因此,可以这样理解,堆是操作系统维护的一块内存,是一个物理概念,而自由存储是C++中通过new与delete动态分配和释放的对象的存储区,是一个逻辑概念。堆与自由存储区并不等价。

参考博客:

1.C++内存管理学习堆和栈 - 云+社区 - 腾讯云 (tencent.com)

2.C/C++程序内存的各种变量存储区域和各个区域详解_jirryzhang的博客-CSDN博客_c++内存区域

3.什么是代码区、常量区、静态区(全局区)、堆区、栈区?_夜风的博客-CSDN博客

posted @ 2020-12-10 15:14  浩楠honer  阅读(138)  评论(0编辑  收藏  举报