C++-内存分配

0.目录

  1. 内存构成
  2. 内存分配

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删除一个指针
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容