首先强调的一点是:每个进程都认为自己独立的享有着计算机的内存
进程会构建自己的虚拟地址空间(进程地址空间),该地址空间所有进程都独立的享有一份,如果是32位机器,则会创建2^32(4G)大小的地址空间 ,如果是64位机器,可以创建2^64大小的地址空间(目前所有的程序都没有这么大),创建出来的虚拟地址空间中(以32位机器为例,一般编译器可以选择使用32位或者64位),其中1G为操作系统所用,剩下3G空间为用户所用,具体实现如下图所示👇 进程的虚拟地址通过页表访问物理内存 物理内存为硬件(计算机的内存 or 手机的内存 都是物理内存) 物理。下图中的内存表示的就是通过页表访问的内存 进程通过页表访问物理内存,并且保证了多个进程访问物理内存之间的不冲突性。
来看一段代码,有助于我们了解C++中的内存分配机制👇
#include<iostream> using namespace std; int globalVar = 1; static int staticGlobalVar = 2; void Func() { static int staticVar = 3; int localVar = 4; int arr[10] = { 1, 2, 3, 4 }; char ch[] = "abcd"; char* pch = "abcd"; int* ptr1 = (int*)malloc(sizeof(int)* 4); int* ptr2 = (int*)calloc(4, sizeof(int)); int* ptr3 = (int*)realloc(ptr2, sizeof(int)* 4); free(ptr1); free(ptr3); } int main() { return 0; }说明:
栈又叫做堆栈,非静态局部变量/函数参数/返回值等,都在其中存放,栈是向下增长的。内存映射段是装在动静态库,用户使用系统接口创建空想内存的地址区。(本节不详细说明)堆,用于程序运行时动态内存管理分配的区域,与栈区相对,向上增长。数据段是用来存储全局变量和静态数据的区域代码段是用来存储代码的区域。分配一个大小size字节的内存块,返回指向该块开头的指针。 新分配的内存块的内容没有进行初始化,保留随机值。
分配num个元素组成的内存块,每个元素的大小都是size大小,并将其所有位初始化为零。分配一个(num * size)字节的零初始化内存块。
先判断当前的指针是否有足够的连续空间,如果有,扩大指针指向的地址,并且将新地址的指针返回,如果空间不够,先按照size指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来内存区域(注意:原来指针是自动释放,不需要使用free),同时返回新分配的内存区域的首地址。即重新分配存储器块的地址
简单来说,释放一个指针所指向的空间
C语言中的管理内存的函数依旧可以在C++中使用,但是有些地方针对于C++的情况下,C语言存在着严重的局限性,所以,C++有引入了新的管理内存的方式new 和 delete进行动态内存管理
注意 动态申请的空间,也要进行释放,因为C/C++都没有内存管理机制,需要用户自己手动管理空间。