内存分配方式
栈 执行函数时,函数局部变量存储单元都在栈上创建,函数执行结束时自动释放。栈内存分配运算置于处理器的指令集中,效率很高,但容量有限。
堆 由new分配的内存块在堆上创建,由delete释放。如果程序员没有释放掉,程序结束后由操作系统回收。
自由存储区 和new类似,是由malloc分配的内存块,用free释放。
静态存储区存放全局变量和静态变量。
常量存储区存放常量,不允许修改。
堆与栈的区别
区别 | 堆 | 栈 |
---|---|---|
管理方式 | 编译器自动管理 | 程序员手动释放,容易产生内存泄漏 |
空间大小 | 32位系统下,可达4G | 1M~2M |
碎片问题 | 频繁new delete造成空间不连续 | 栈先进后出,空间连续 |
生长方向 | 向上(内存地址增加) | 向下(内存地址减小) |
分配方式 | 动态分配 | 静态和动态 |
分配效率 | C/C++函数库提供,低 | 底层提供支持,高 |
堆 C/C++函数库提供,如为分配一块内存,库函数会按照一定算法再堆内存中搜索可用的栈足够大小的空间,如果没有就调用系统功能增加程序数据段的内存空间,效率低
机器系统提供的数据结构,计算机在底层提供支持:分配专门的寄存器存放地址,有专门指令执行,效率高
内存池
new delete
为什么要重载
和malloc&free的区别
1. malloc&free是C/C++标准库函数,不在编译器控制范围内,new&delete是C++运算符,可以申请动态内存和释放内存。
2. 对于非内部数据类型的对象而言,malloc/free无法满足动态对象的要求。
3. 对象创建时执行构造函数函数,消亡前执行析构函数。因此需要能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。
4. 为什么不淘汰malloc/free,因为c++经常调用c函数,c程序只能用malloc/free管理动态内存
void UseMallocFree(void)
{
Obj *a = (obj *)malloc(sizeof(obj)); // 申请动态内存
a->Initialize(); // 初始化
//…
a->Destroy(); // 清除工作
free(a); // 释放内存
}
void UseNewDelete(void)
{
Obj *a = new Obj; // 申请动态内存并且初始化,模拟构造函数功能
//…
delete a; // 清除并且释放内存,模拟析构函数功能
}
常见错误&对策
- 内存分配未成功却使用
使用前检查指针是否为NULL进行防错处理
- 如果指针p是函数参数,则函数入口处用assert(p!=NULL)
- 如果使用malloc或new申请内存,应该if(p==NULL)或if(p!=NULL)检查
- 内存分配成功未初始化
内存缺省初值没有统一标准。 - 内存分配成功且初始化,但越界
尤其在for循环中 - 忘记释放内存,内存泄漏
直到内存耗尽。malloc和free,new和delete配对使用 - 释放内存继续使用
- 对象调用关系复杂,应重新设计数据结构,解决对象管理混乱的局面
- 不能return指向栈内存的指针或引用
- free或delete释放了内存后,没有把指针置空,产生野指针
内存耗尽
如果申请动态内存时找不到足够大的内存,malloc和new将返回NULL指针。
处理
- 判断NULL,如果是则用return终止
- 判断NULL,如果是则用exit(1)终止整个程序
- 为malloc/new设置异常处理函数
不编写出错程序,操作系统自己解决?
不行,32位以上应用程序,无论怎样使用malloc/free,几乎不可能“内存耗尽”,因为32位操作系统支持“虚存”,内存用完自动用硬盘空间代替。