内存管理
内存管理
primatives
array new
Object 类型的数组通过一个 cookie 来管理,具体保存了数组长度等信息。
Object *p = new Object[3]; // 初始化一个长度为3的 Object 类型的数组
delete[] p; // 释放 p 数组,这里的中括号不能丢,带[] 调用三次 dtor
如果类里面存在指针变量,那么 delete 忘记带中括号的时候,只会调用一次析构函数,此时剩余两个指针指向的对象不会被回收,发生内存泄漏。
定点 new / placement new
在指定内存位置 new 一个对象,该内存地址是已经分配好的内存。
New(addr) A(i) -> 其中 addr 是指定内存位置,A(i)是构造函数。
调用 delete 发生什么
- 首先调用对象的析构函数 dtor
- 然后 free 内存
分配内存的途径
Foo *p = new Foo(x);
delete p;
=======================================
会转换成下面的句子,也可以直接使用下面的形式
=======================================
1, Foo *p = (Foo *)operator new(sizeof(Foo));
2, new(p)Foo(x);
1,p->~Foo();
2,operator delete(p);
如果要对内存管理做一些操作可以重载 Foo::operator new() 函数 和 Foo::operator delete() 函数。
容器的内存分配方式
Container<T>
T* p = allocate();
construct();
destroy();
deallocate p;
重载
1,重载全局的 ::operator new / ::operator delete
void *myAlloc(size_t size) {
return malloc(size);
}
inline void* operator new(size_t size) {
xxx;
return myAlloc(size);
}
2, 重载类的 operator new/operator delete
Foo *p = new Foo;
class Foo {
public:
void * operator new(size_t);
void operator delete(void *, size_t);//第二个参数可以不要.
static void * operator new[](size_t);
static void operator delete[](void *, size_t);
}
重载之后可以接管内存管理,并且做一个小的内存池。
RAII
- resource aquisition is initialization 取得资源的时机便是初始化的时机
目的 =》将资源放到对象里面来管理(以对象管理资源)
- 管理对象运用析构函数来释放资源。(一旦对象被销毁或者离开作用于,就会调用析构函数来销毁对象)
- 智能指针 auto_ptr 能够实现这样的观念
auto_ptr<Investment> ptr(createInvestment()); // 1, 调用 factor 构造函数来创建 investment 对象 2, 使用 ptr 这个对象 3,在使用完后只能指针自动调用 Investment 析构函数。
但是这样的做法有点问题,如果多个 ptr 指向同一份资源,那么都释放这个资源就会出现问题,因此在创建其他的智能指针的时候会复制前一个智能指针,并且将前一个智能指针置为 null。
此外,auto_ptr 析构函数调用的是 delete 而不是 delete[],因此不能用来管理 string 数组资源
- 除了 auto_ptr 外,还有 tr1::shared_ptr 是个引用计数型指针,不得不想到 JVM 里面的引用计数法。追踪有多少人使用该资源,并且在无人使用该资源的时候释放掉。该方法常用。
void f() {
tr1::shared_ptr<Investment> ptr(createInvestment());
tr1::shared_ptr<Investment> ptr2(ptr1);
ptr1 = ptr2;
}
可以重载 new() / delete()
重载 operator new() , 第一参数必须是 size_t,
如果重载某个 operator new ,在分配内存后,新建一个对象失败,需要抛出异常,这样就可以自动调用 operator delete 来释放内存。
内存管理目标
速度
内存池的作用:
1)避免频繁地调用 malloc
2)能够避免大量的cookie,从而节省内存。
采用 union {
}
使用同一个东西的前n个字节当做地址。