此文用以加深记忆,督促学习的目的
在线阅读http://book.51cto.com/art/201202/317549.htm
0 区分内存分配的方式
内存管理的水平是衡量高手和菜鸟的一个不成为的约定
一个程序加载到计算机内存里,可形成一个运行空间,大致分为:代码区、数据区、堆区、栈区
* 代码区:存放的是程序的执行代码
* 数据区:存放的是全局数据、常量、静态变量等
* 堆区:存放的是动态内存,供程序使用
* 栈区:存放的是程序中所用到的局部数据
+ 代码区是我们不能在代码中控制的,其他三个区是编码过程中利用的
+ 数据区自由存储区、全局/静态存储区和常量存储区
+ 自由存储区:是有malloc等分配的内存块,需要使用free来释放
+ 全局/静态存储区: 全局变量和静态变量被分配到同一块内存中
+ 常量存储区: 存放常量,不允许修改
new/delete 与new[]/delete[]必须配对使用
* delete删除对象时,编译器只会将指针所指向的对象当作单个对象来处理
1 区分new的三种形态
* new operator
这是我们使用最多的
string *pStr = new string("Memory Management");
int *pInt = new int(2011);
* operator new
class A
{
public:
A(int a);
~A();
void* operator new(size_t size);
...
};
void* A::operator new(size_t size)
{
cout<<"Our operator new...");
return ::operator new(size);
}
* placement new
placement new是用来实现定位构造的,可以通过它来选择合适的构造函数。虽然通常情况下,构造函数是由编译器自动调用的,但是不排除你有时确实想直接手动调用,比如对未初始化的内存进行处理,获取想要的对象,此时就得求助于一个叫做placement new的特殊的operator new了
#include
#include "ClassA.h"
int main()
{
void *s = operator new(sizeof(A));
A* p = (A*)s;
new(p) A(2011); //p->A::A(2011);
... // processing code
return 0;
}
总结一下:
如果是在堆上建立对象,那么应该使用 new operator,它会为你提供最为周全的服务。
如果仅仅是分配内存,那么应该调用operator new,但初始化不在它的工作职责之内。如果你对默认的内存分配过程不满意,想单独定制,重载operator new 是不二选择。
如果想在一块已经获得的内存里建立一个对象,那就应该用placement new。但是通常情况下不建议使用,除非是在某些对时间要求非常高的应用中,因为相对于其他两个步骤,选择合适的构造函数完成对象初始化是一个时间相对较长的过程
2 new内存失败后的正确处理
当使用new申请一块内存失败时,抛出异常std::bad_alloc是C++标准中规定的标准行为,所以推荐使用try{ p = new int[SIZE]; } catch( std::bad_alloc ) { ... }的处理方式。但是在一些老旧的编译器中,却不支持该标准,它会返回NULL,此时具有C传统的Test_for_NULL代码形式便起了作用。所以,要针对不同的情形采取合理的处置方式。
3 了解new_handler的所作所为
通常,一个好的new-handler函数的处理方式必须遵循以下策略之一:
Deinstall the new-handler(卸载new-handler)
Make more memory available(使更大块内存有效)
Install a different new-handler(装载另外的new-handler)
Throw an exception(抛出异常)
Not return(无返回)
直接调用abort或exit结束应用程序。
4 借助工具检测内存泄露问题
* linux下的Valgrind和Rational Purify
5 小心翼翼的重载operator new/ operator delete
6 用智能指针管理通过new创建的对象
7 使用内存池技术提高内存申请效率和性能
经典的内存池实现原理如下:
class MemPool
{
public:
MemPool(int nItemSize, int nMemBlockSize = 2048)
: m_nItemSize(nItemSize),
m_nMemBlockSize(nMemBlockSize),
m_pMemBlockHeader(NULL),
m_pFreeNodeHeader(NULL)
{
}
~ MemPool();
void* Alloc();
void Free();
private:
const int m_nMemBlockSize;
const int m_nItemSize;
struct _FreeNode
{
_FreeNode* pPrev;
BYTE data[m_nItemSize - sizeof(_FreeNode*)];
};
struct _MemBlock
{
_MemBlock* pPrev;
_FreeNode data[m_nMemBlockSize/m_nItemSize];
};
_MemBlock* m_pMemBlockHeader;
_FreeNode* m_pFreeNodeHeader;
};
Boost库同样对该技术提供了较好的支持:
pool的析构函数会释放pool占用的内存。