内存管理

84 阅读3分钟

内存管理

内存管理

primatives

array new

Object 类型的数组通过一个 cookie 来管理,具体保存了数组长度等信息。

Object *p = new Object[3];  // 初始化一个长度为3Object 类型的数组
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个字节当做地址。