什么是动态内存?
- 用户自己申请的内容空间并且用完之后需要动态进行释放的空间
- 动态: 用户申请由用户释放
为什么需要进行动态内存申请呢?
- 在内存不同的区域存放不同的是不同的数
- 而用户数据能够存储的位置: 栈 堆
- 用户的数据可能非常大,在栈区中存储补下,因此需要更大的内存空间类存储用户的数据更大的内存空间用户需要向操作系统来进行获取
- 栈空间(函数运行时的栈帧,随函数运行而创建,随函数结束而回收,回收之后,函数中局部变量的数据就没有意义了, 但是有些情况下,我们需要将程序运行期间产生的数据带出函数之外)
动态内存申请时,需要注意什么问题?
- 一般用多少申请多少
- 在使用时,不要越界,用完之后记得及时归还
C语言中是如何来进行内存申请的?
- 必须要包含对应的头文件
- 使用动态内存申请的函数: malloc / calloc / realloc
- 空间使用完成之后一定要归还: free
malloc:
- C语言提供了一个动态内存开辟的函数:
void* malloc (size_t size);
- 这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指。
- 如果开辟成功,则返回一个指向开辟好空间的指针。
- 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
- 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
- 如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。
calloc:
- C语言还提供了一个函数叫 calloc , calloc 函数也用来动态内存分配。原型如下
void* calloc (size_t num, size_t size);
- 函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。
- 与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0。
realloc:
- realloc函数的出现让动态内存管理更加灵活。
- 有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时候内存, 我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整。
- 函数原型如下:
void* realloc (void* ptr, size_t size);
- ptr 是要调整的内存地址
- size 调整之后新大小
- 返回值为调整之后的内存起始位置。
- 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。
- realloc在调整内存空间的是存在两种情况:
- 情况1:原有空间之后有足够大的空间
-
当是情况1 的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。
-
-
情况2:原有空间之后没有足够大的空间
- 当是情况2 的时候,原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小的连续空间来使用。这样函数返回的是一个新的内存地址。
- 情况1:原有空间之后有足够大的空间
内存区域划分:
- 内核空间:
- 放操作系统的代码以及数据
- 只有操作系统能够进行访问,如果用户想要进行访问的话,必须通过专门的API函数来访问
- 栈:
- 存放和函数调用相关的数据:
- 局部变量
- 函数参数
- 一些寄存器的薪资
- 存放和函数调用相关的数据:
- 堆:
- 程序员动态申请的空间就在堆上
- 数据段:
- 全局变量
- static修饰的变量
- 代码段:
- 该部分的内容是不允许被修改的: 代码 和 常量
C++内存管理方式:
C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力而且使用起来比较麻烦,因此C++又提出 了自己的内存管理方式:通过new和delete操作符进行动态内存管理。
new和delete不是函数,是C++中的操作符或者关键字
- new / delete操作内置类型
- new / delete的实现原理
- 内置类型
- 如果申请的是内置类型的空间,new和malloc,delete和free基本类似,
- new / delet申请和释放的是单个元素的空间,new[] / delete[] 申请的是连续空间,而且new在申请空间失败时会抛异常, malloc会返回NULL。
- 自定义类型
-
new的原理
-
调用operator new函数申请空间
-
在申请的空间上执行构造函数,完成对象的构造
-
-
delete的原理
-
在空间上执行析构函数,完成对象中资源的清理工作
-
调用operator delete函数释放对象的空间
-
- new T[N]的原理
- 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请
- 在申请的空间上执行N次构造函数
- delete[]的原理
- 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理
- 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间
-
- 内置类型
malloc / free | 必须要匹配起来使用,否则可能会造成内存泄漏或者程序崩溃 |
new / delete | |
new[] / delete[] |
malloc / free和new / delete的区别:
- 共同点:
- 都是从堆上申请空间,并且需要用户手动释放。
- 不同的地方是:
- malloc和free是函数,new和delete是操作符
- malloc申请的空间不会初始化,new可以初始化
- malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可
- malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型
- malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常
- 申请自定义类型对象时,malloc / free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理