文章目录
一、内存分配方式
1.内存区域
(1)栈
局部存储,函数生命周期结束时销毁
(2)堆
malloc与free管理
(3)自由存储区
new与delete管理,默认实现为堆,程序员可重载操作符产生其他实现
(4)全局/静态存储区
合并.data与.bss段的存储
(5)常量存储区
2.内存问题分析
1.内存碎片
频繁申请释放小块内存影响内存性能
(1)原因
- 内部碎片:内存分配的对齐原则导致产生碎片
- 外部碎片:频繁的分配与回收物理页面
(2)解决
对每个类重载new和delete运算符,从内存缓冲池申请空间
2.内存泄露
指针先于内存空间被释放导致内存空间无法引用和回收
(1)原因:
malloc和free不能对应使用
(2)细节
【new[ ]与delete[ ] 匹配问题】
内置类型无需匹配,自定义类型不匹配会出现内存泄露
int *p = new int[100];
delete[] p;
【堆上有指针的问题】
先释放子节点,再释放父节点
free(p->np);
free(p);
【注意多态特性】
- delete void*类型时不调用析构函数
//对应类型承接,delete时调用对应析构函数
//void*类型承接,delete时无析构函数调用
Object* a = new Object(10, 'A');
void* b = new Object(20, 'B');
delete a; //释放a,调用析构函数
delete b; //释放b,不调用析构函数
- 父类析构函数问题
//若父类析构函数是virtual,p调用子类析构函数
//若父类析构函数非虚函数,p调用父类析构函数,子类特性未释放,内存泄露
person *p = new child(20,'B');
delete p;
【注意指针】
//错误写法
void my_malloc(void *p, int size)
{
//p为函数创建的指针的副本,函数结束时销毁
p = malloc(sizeof(int)*size);
}
//正确写法
void my_malloc(void **p, int size) or void my_malloc(void &(*p), int size)
{
*p = malloc(sizeof(int)*size);
}
二、new与delete相关
1.概述
new{
//分配内存,可重载
operator new{
//分配堆内存
malloc
}
//调用构造函数
ctor
}
2.细节
1.STL空间配置器
- allocator:配置器默认实现,内部调用operator new
//C++11 改名为 new_allocator
int *p = allocator<int>().allocate(512, (int*)0);
allocate<int>().deallocate(p, 512)
- alloc:二级配置器实现,性能更好
//C++11 改名为__pool_alloc
vector<string, __gnu_cxx::__pool_alloc<string>> vec;
/*
两级配置器:
(1)配置区超过128byte:一级配置器
malloc + free + set_new_handler
(2)配置区小于128byte:二级配置器
内存池 + 自由链表
*/
2.new、operator new、placement new
-
new: 内置函数, 分配空间 + 调用构造函数
T *p = new T();
-
operator new: 可重载, 分配内存
void *memory = operator new(sizeof(string));
-
placement new: 标准operator new, 在已有内存创建对象
void *operator new( size_t, void * p ) throw() { return p; }
T *pb = new(pa) T