0.目录
- 内存构成
- 内存分配
1.内存构成
C的内存基本上分为4部分:静态存储区、堆区、栈区以及常量区。
- 栈
- 由编译器自动分配释放
- 函数体中定义的变量通常是在栈上
- 堆
- 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收
- 用malloc, calloc, realloc等分配内存的函数分配得到的就是在堆上
- 全局区(静态区)
- 全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域(C++中已经不再这样划分),程序结束释放;
- 在所有函数体外定义的是全局量
- 加了static修饰符后不管在哪里都存放在全局区
- 常量区
- 专门放常量的地方,程序结束释放
- 函数中的"adgfdf"这样的字符串存放在常量区
在C++中内存分成5个区,分别是堆、栈、全局/静态存储区、常量存储区和代码区;
- 栈(stack)
就是那些由编译器在需要的时候分配,在不需要的时候自动清楚的变量的存储区,里面的变量通常是局部变量、函数参数等。 - 堆(heap)
就是那些由new分配的内存块,他们的释放编译器不去管,由我们的应用程序去控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。 - 全局/静态存储区(.bss段和.data段)
全局变量和静态变量被分配到同一块内存中,在以前的C语言中,全局变量又分为初始化的和未初始化的,在C++里面没有这个区分了,他们共同占用同一块内存区。 - 常量存储区(.rodata段)
这是一块比较特殊的存储区,他们里面存放的是常量,不允许修改(当然,你要通过非正当手段也可以修改)。 - 代码区 (.text段)
存放代码(如函数),不允许修改(类似常量存储区),但可以执行(不同于常量存储区)。
根据c/c++对象生命周期不同,c/c++的内存模型有三种不同的内存区域,即:自由存储区,动态区、静态区。
- 自由存储区:局部非静态变量的存储区域,即平常所说的栈;
- 动态区: 用new ,malloc分配的内存,即平常所说的堆;
- 静态区:全局变量,静态变量,字符串常量存在的位置;
注:代码虽然占内存,但不属于c/c++内存模型的一部分;
在linux系统中,程序在内存中的分布如下所示:
低地址
.text---> .data --->.bss
--->heap(堆) --> unused <-- stack(栈)
-->env
高地址
其中 :
- .text 部分是编译后程序的主体,也就是程序的机器指令。
- .data 和 .bss 保存了程序的全局变量,.data保存有初始化的全局变量,.bss保存只有声明没有初始化的全局变量。
- heap(堆)中保存程序中动态分配的内存,比如C的malloc申请的内存,或者C++中new申请的内存。堆向高地址方向增长。
- stack(栈)用来进行函数调用,保存函数参数,临时变量,返回地址等。
BSS 是“Block Started by Symbol”的缩写,意为“以符号开始的块”。BSS是Unix链接器产生的未初始化数据段。其他的段分别是包含程序代码的 “text”段和包含已初始化数据的“data”段。BSS段的变量只有名称和大小却没有值。此名后来被许多文件格式使用,包括PE。“以符号开始的块” 指的是编译器处理未初始化数据的地方。BSS节不包含任何数据,只是简单的维护开始和结束的地址,以便内存区能在运行时被有效地清零。BSS节在应用程序 的二进制映象文件中并不存在。
在采用段式内存管理的架构中(比如intel的80x86系统),bss段(Block Started by Symbol segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域,一般在初始化时bss 段部分将会清零。bss段属于静态内存分配,即程序一开始就将其清零了。
比如,在C语言之类的程序编译完成之后,已初始化的全局变量保存在.data 段中,未初始化的全局变量保存在.bss 段中。
2.内存分配
2.1 malloc
void *malloc(unsigned int size)
在内存的动态分配区域中分配一个长度为size的连续空间,如果分配成功,则返回所分配内存空间的首地址,否则返回NULL,申请的内存不会进行初始化。
2.2 calloc
void *calloc(unsigned int num, unsigned int size)
按照所给的数据个数和数据类型所占字节数,分配一个 num * size 连续的空间,calloc申请内存空间后,会自动初始化内存空间为0。
2.3 realloc
void *realloc(void *ptr, unsigned int size)
动态分配一个长度为size的内存空间,并把内存空间的首地址赋值给ptr,把ptr内存空间调整为size,申请的内存空间不会进行初始化。
2.4 new
动态分配内存的运算符,自动计算需要分配的空间,在分配类类型的内存空间时,同时调用类的构造函数,对内存空间进行初始化,即完成类的初始化工作。动态分配内置类型是否自动初始化取决于变量定义的位置,在函数体外定义的变量都初始化为0,在函数体内定义的内置类型变量都不进行初始化。
new[]要求元素对象的类型必须具有默认构造函数(内建类型的“默认构造函数”是什么也不做),否则将不能使用new[]。
2.5 new与malloc
- new是运算符,malloc()是一个库函数;
- new会调用构造函数,malloc不会;
- new返回指定类型指针,malloc返回void*指针,需要强制类型转换;
- new会自动计算需分配的空间,malloc不行;
- new可以被重载,malloc不能。
2.6 delete
- delete会调用对象的析构函数,和new对应
- delete是C++的运算符
- 对于内建简单数据类型,delete和delete[]功能是相同的。对于自定义的复杂数据类型,delete和delete[]不能互用。delete[]删除一个数组,delete删除一个指针