- new/[], delete/[] 解析,placement new定点分配
- new handler
- per-class allocator
- static allocator
- std::alloc
- std::alloc_pool
new/[], delete/[] 解析
Complex* c = new Complex(1,2);
1. 分配内存
2. 指针转型
3. 调用对象构造函数
try{
void* mem = operator new(sizeof(Complex));
pc = static_cast<Complex*>(mem);
pc->Complex::Complex(1,2);//不可以直接调用想要直接调用构造函数可以使用placement new(new(p)Complex(1,2))
}catch(std::bad_alloc){
}
void*operator new(size_t size,const std::nothrow _t&)_THROW()
{
void *p;
while((p==malloc(size)) ==0){
_TRY_BEGIN
if(_callnewh(size) ==0) break;//分配失败调用new handler 可以自定义
_CATCH(std::bad_alloc) return 0;
_CATCH_END
}
return p;
}
delete 分两个步骤
delete pc
1. 调用析构函数
2. 释放空间
pc->~Compelx();
operator delete(pc);
void __cdecl operator delete(void* p){
free(p);
}
补充:__cdecl __stdcall
区别,一个是调用这清理栈,一个是自身清理
http://blog.csdn.net/j_jeff/article/details/41693737
array new
complex* pca = new Complex[3];
delete[] pca;//如果只调用delete pca,则不会调用析构函数有可能会造成内存泄露(对象管理的那部分内存 即指针指向的)
new /delete调用路径
//1
Foo* p = newFoo(x);
delete p;
//2
Foo* p = (Foo*)operator new(sizeof(Foo));
new(p)Foo(x);
p->~Foo();
operator delete(p);
//可以调用member new/delete
Foo::operator new(size_t);
Foo::operator delete(void*);
//全局new/delete
::operator new(size_t);
::operator delete(void*);
//3
malloc(size_t);
free(void*)
例子重载全局operator new/delete
//注意不可以方在namespace中
void* myAlloc(size_t size){return malloc(size);}
void myFree(void* ptr){ free(ptr);}
inline void* operator new(size_t size){
return myAlloc(size);
}
inline void* operator[](size_t size){return myAlloc(size);}
inline void operator delete(void* ptr){myFree(ptr);}
inline void operator delete[](void* ptr){myFree(ptr);}
重载class member operator new() 可以重载多个,但是每一个版本的声明第一个参数必须是size_t,其余的采纳湖一new所指定的placement arguments 为初始值。出现于new(args) args即所谓的placement arguments.
Foo* pf = new(330,’c’)Foo;
也可以重载per-class operator delete 但是只有在GNU2.9之前当ctor出现异常时才会调用,4.9之后即便ctor出现异常也不会调用了。
placement new定点分配
//示例
class Foo{
public:
Foo(){cout << "Foo::Foo" <<endl;}
Foo(int){cout << "Foo::Foo(int)" << endl;}
void* operator new(size_t size){
return malloc(size);
}
//标准库提供的placement new 形式
void*operator new(size_t size,void* start){
return start;
}
void* operator new(size_t size, long extra){
return malloc(size + extra);
}
void* opeartor new(size_t size,long extra,char init){
return malloc(size + extra);//size_t 必须在最前面,long不可以
}
};
注意所有 class中的new,delete默认都是static的要在构造之前就调用
new handler
当opeartor new 分配内存失败时会抛出一个bad_alloc exception ,抛出之前可以指定一个handler来处理:
typedef void(*new_handler)()[
new_handler set_new_handler(new_handler p)throw();
//可以通过调用set_new_handler 来指定处理函数
//一般只有两种处理方式1. 让更多的memory可用,2.调用abort()或者exit()
参考:
http://www.cnblogs.com/jerry19880126/p/3722531.html
per-class allocator
class Screen{
public:
Screen(int x):_i(x){};
int get(){return _i;}
void*operator new(size_t);
void operator delete(void*, size_t);
private:
Screen* next;
static Screen* freeStore;
static const int screenChunk;
private:
int _i;
};
Screen* Screen::freeStore = 0;
const int Screen::screnChunk = 24;
void* Screen::operator new(size_t size)
{
Screen *p;
if(!freeStore){
//linked list 是空的所以申请一大块
size_t chunk = screenChunk * size;
freeStore = p =
reinterpret_cast<Screen*>(new char[chunk]);
//将大块内存分割成片,当作linked list 串起来备用。
for(;p!=freeStore[screenChunk -1];++p)
p->next = p+1;
p->next = nullptr;
}
p = freeStore;
freeStore = freeStore->next;
return p;
}
void Screen::operator delete(void* p;size_t size)
{
//将deleted object 插回freelist
(static_cast<Screen*>(p)) ->next = freeStore;
freeStore = static_cast<Screen*>(p);
}
例2
Class Airplane{
private:
struct AirPlaneRep{
unsigned long miles;
char type;
};
private:
union{
AireplaneRep rep;//针对使用中的object
AirePlane* next;//针对freelist上的object
};
public:
unsigned long getMiles(){return rep.miles;}
char getType(){return rep.types;}
void set(unsigned long m, char t)
{
rep.miles=m; rep.type=t;
}
public:
static void* operator new(size_t size);
static void operator delete(void* deadObject,size_t size);
private:
static const int BLOCK_SIZE;
static Airplane* headOfFreeList;
};
Aireplane* Airplane::headOfFreeList = nullptr;
const int Airplane::BLOCK_SIZE = 512;
void* Airplane::operator new(size_t size)
{
//如果大小有误转交给::operator new;(当继承发生时)
if(size !=sizeof(Airplane))
return ::operator new(size);
Airplane* p = headOfFreeList;
if(p)//如果p有效就把头部下移一位传回去
headOfFreeList = p->next;
else{
//freelist 已空,就申请一块大内存
Airplane* newBlock = static_cast<Airplane*>
(::operator new(BLOCK_SIZE*sizeof(Airplane)));
//将小块串起来避开第一个位置(已经使用需要回传)
for(int i = 1; i < BLOCK_SIZE -1; ++i)
newBlock[i].next = &newBlock[i+1];
newBlock[BLOCK_SIZE-1] = nullptr;//list 结束
p=newBlock;
headOfFreeList = &newBlock[1];
}
return p;
}
void Airplane::operator delete(void* deadObject,size_t size){
if(deadOnject == nullptr)return;
if(size != sizeof(Airplane))
{
::operator delete(deadObject);
return;
}
AirPlane* carcass =
static_cast<Airplane*>(deadObject);
carass->next = headOfFreeList;
headOfFreelist = carass;
}
static allocator
上面的做法需要对每一个class重写一个member operator new 和member operator delete
解决方法将之包装成一个memory allocator 重复使用。
class allocator
{
private:
struct obj{
struct obj* next;//embeded pointer
};
public:
void* allocate(size_t);
void deallocate(void*,size_t)
private:
obj* freeStore = nullptr;
const int CHUNK = 5;
};
void allocatorallocate(size_t size){
obj* p;
if(freeStore){
//linked list 为空申请一块大内存
size_t chunk = CHUNK*size;
freeStore = p = (obj*)malloc(chunk);
//将大块分为小块串起来
for(int i = 0; i < CHUNK - 1; ++i){
p->next = (obj*)((char*)p + size);
p = p->next;
}
p->next = nullptr;
}
p = freeStore;
freeStore = freeStore->next;
return p;
}
void allocator:: deallocate(void* p,size_t){
((obj*)p)-> next = freeStore;
freeStore = (obj*)p;
}
使用
class Foo{
private:
long l;
string str;
static allocator myAlloc;
public:
Foo(long l)l(l){};
static void* operator new(size_t size){
return myAlloc.allocate(size);
}
static void* operator delete(void* phead,size_t size){
return myAlloc.dealloacte(phead,size);
}
};
注意的一点是staic operator new/new[] 可以是=delete但是不能=default
std::alloc
vc6 和GNU2.9 allocator 实现
template<class _Ty>
class allocator {
public:
typedef _SIZT size_type;
typedef _PDFT diffeence_type;
typedef _Ty _FARQ *pointer;
typedef _Ty value_type;
pointer allocate(size_type _N, const void*){
return (_Allocate((diffeence_type) _N,(pointer)0));
}
void deallocate(void _FARQ * _P, size_type)
{operator delete(_P);}
};
template<class _Ty> inline
_Ty FARQ * _Allocate(_PDFT _N, _Ty _FARQ*){
if(_N<0) _N = 0;
return ((_Ty _FARQ*) operator new((SIZT)_N* sizeof(_Ty)));
}
使用
template<class _Ty,class _A = allocator<_Ty>>
class vector{...};
std::alloc_pool
freelist 有16个node每个node代表可以存放的内存块大小最小为4 Byte 依次*2增长。示例:
分配一个32 的内存, 先检查 freelist[3] 是否有空余块,如果有则返回,如果没有则malloc 132*20*2 +RoundUp() = 1280大小内存, 20*2 为固定值,用来多申请一些备用, RoundUp() 每次申请在同一node 上都会增大,并且还用来调整内存对齐。这1280种640 拿来切片成20 个放在freelist[3]上,剩下640备用。当其他node也有内存申请时 这些内存则连接到其他node上使用。但是,当,其他node需要内存分配但是备用的内存不够那个node 所需的一个空间时,则就近向freelist 头搜索到最近的node 将剩余备用内存切片并挂到那个node上,然后再在所需的node上malloc申请内存。当全部内存申请完不够alloc时比如需要80个byte时,则就近搜索那个node上面的内存剩余够用将其挂在80那个node上供其使用。如果还是找不到,则折半需求变为40看系统有没有空间,如果没有再折半最终获取到所需要的内存。
具体实现待补充。。。。