1,C++中有5个内存的分配区:堆,栈,常量存储区,自由存储区,全局\静态存储区。

    自由存储区,用malloc和free分配和释放,同堆差不多。

    全局\静态存储区:用于存储分配的全局和静态变量。

2,堆和栈的区别

    主要的区别由以下几点:

  1、管理方式不同;堆有编译器管理,栈由程序员管理,比较容易产生memory leak

  2、空间大小不同;在32位中,堆理论的大小是4G,所以没有什么限制,但是栈的默认大小是1M,可以设置,但是如果长度过大,会增加内存的开销和启动的时间。

  3、能否产生碎片不同;堆用new和delete分配,肯定会造成空间不连续,比较容易产生碎片,栈是按照严格的先进后出的,所以不会产生碎片。

  4、生长方向不同;堆是按照地址增加的方向分配的,栈是按照地址减小的方向分配的。

  5、分配方式不同;对是动态分配的,没有静态分配的,栈可以是动态分配,也可以是静态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。

  6、分配效率不同;栈是机器系统提供的数据结构,从底层支持栈的操作,并有专门的指令。所以效率比较高。堆是有C/C++的库来完成的,它的机制很复杂,先需要寻找能分配下的内存地址,然后才能分配。并且还容易造成内存碎片,所以效率比较低。

从这里我们可以看到,堆和栈相比,由于大量new/delete的使用,容易造成大量的内存碎片;由于没有专门的系统支持,效率很低;由于可能引发用户态和核心态的切换,内存的申请,代价变得更加昂贵。所以栈在程序中是应用最广泛的,就算是函数的调用也利用栈去完成,函数调用过程中的参数,返回地址,EBP和局部变量都采用栈的方式存放。所以,我们推荐大家尽量用栈,而不是用堆。

3,重载new和delete修饰符

一个防止堆破碎的通用方法是从不同固定大小的内存持中分配不同类型的对象。对每个类重载new 和delete就提供了这样的控制。

可以很容易地重载new 和 delete 操作符,如下所示:

void * operator new(size_t size)

{

void *p = malloc(size);

return (p);

}

void operator delete(void *p);

{

free(p);

}

也可以对单个类的new 和 delete 操作符重载。这是你能灵活的控制对象的内存分配。

class TestClass {

public:

void * operator new(size_t size);

void operator delete(void *p);

// .. other members here ...

};

void *TestClass::operator new(size_t size)

{

void *p = malloc(size); // Replace this with alternative allocator

return (p);

}

void TestClass::operator delete(void *p)

{

free(p); // Replace this with alternative de-allocator

}

  所有TestClass 对象的内存分配都采用这段代码。更进一步,任何从TestClass 继承的类也都采用这一方式,除非它自己也重载了new 和 delete 操作符。通过重载new 和 delete 操作符的方法,你可以自由地采用不同的分配策略,从不同的内存池中分配不同的类对象。

 必须小心对象数组的分配。你可能希望调用到被你重载过的new 和 delete 操作符,但并不如此。内存的请求被定向到全局的new[ ]和delete[ ] 操作符,而这些内存来自于系统堆。

  C++将对象数组的内存分配作为一个单独的操作,而不同于单个对象的内存分配。为了改变这种方式,你同样需要重载new[ ] 和 delete[ ]操作符。

class TestClass {

public:

void * operator new[ ](size_t size);

void operator delete[ ](void *p);

// .. other members here ..

};

void *TestClass::operator new[ ](size_t size)

{

void *p = malloc(size);

return (p);

}

void TestClass::operator delete[ ](void *p)

{

free(p);

}

int main(void)

{

TestClass *p = new TestClass[10];

// ... etc ...

delete[ ] p;

}

但是注意:对于多数C++的实现,new[]操作符中的个数参数是数组的大小加上额外的存储对象数目的一些字节。在你的内存分配机制重要考虑的这一点。你应该尽量避免分配对象数组,从而使你的内存分配策略简单。

4,常见的内存错误

【1】:内存没有分配成功,但是却使用了这个分配的内存。(办法是判断一下是否为NULL assert(P == NULL)).

【2】:分配了内存却没有初始化,及时初始化为0.

【3】:数组越界,特别要当心发生“多1”或者“少1”操作。

【4】:释放了内存没有置为空,用free或delete释放了内存之后,立即将指针设置为NULL,防止产生“野指针”。

【5】:释放了的内存还去引用

【6】:new和delelte要成对出现(malloc和free也是一样)