C/C++程序将内存分为那些区?为什么进行分区?
- 分区
- 栈区:由编译器自动分配和释放,用于存放函数的参数值、局部变量等
- 堆区:由程序员手动分配和释放,用于动态内存分配
- 全局区:用于存放全局变量和静态变量。程序开始运行时分配内存,结束时释放
- 常量区:存放常量数据,如字符串常量,const修饰的变量等
- 代码区:存放函数体的二进制代码。是只读的
- 分区原因
- 管理方便
- 数据保护
- 支持动态分配
- 提高程序运行效率
malloc实现原理
- malloc的实现依赖操作系统提供的底层内存分配接口
- brk/sbrk:通过移动进程的堆顶指针来扩展或收缩堆空间
- mmap:通过映射文件或匿名区域到进程地址空间,分配较大内存
- 分配的内存独立于堆,释放时直接归还操作系统,减少碎片
new和delete的实现原理
new(opeartor new + 构造函数)
- 调用void* operator new(size_t size)申请空间
- 循环调用malloc申请空间
- 如果malloc申请空间成功则返回,失败先检测用户是否设置空间不足应对措施,如果提供调用malloc申请,如果没有提供,抛出bad_alloc异常
- 对申请好的空间调用构造函数进行初始化
delete(析构函数 + operator delete)
- 调用对应类型的析构函数,完成对象中资源的清理工作
- 调用void operator delete(void* p)函数完成空间的释放工作,而函数中真正的释放是使用free进行的
new T[N]
- 调用void* operator new[](size_t size)函数来申请空间
- 该函数中实际调用void* operator new来完成申请的
- 调用N次构造函数,对N个对象的空间从前往后进行初始化
tedele[] p
- 调用N次析构,完成空间中N个对象中的资源清理工作
- 调用void operator delete[](void* p)
- 实际是调用void operator delete(void* p)完成工作
new/delete和malloc/free的区别
- 相同点
- 都是用来动态申请内存空间
- 申请的空间在用完后都必须手动释放
- 不同点
- malloc和free是函数,new和delete是操作符
- malloc申请不会初始化,new可以初始化
- malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可
- malloc的返回值为void*,在使用时必须强转,new不需要
- malloc申请失败时,返回值是NULL,因此使用时需要判空,new不需要,但时new要捕获异常
- 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造和析构
什么是内存泄漏?内存泄漏的危害?
- 定义:内存泄漏是程序在运行过程中,动态分配了内存空间,但使用完毕后,没有及时将这些内存释放回系统,导致这部分内存无法再次利用,随着程序的运行,泄漏的内存不断积累
- 内存泄漏的危害
如何避免内存泄漏