内存池使得全局new失败?
最近偶作了一个内存缓冲池,但它运行时使得全局 ::new 的 HeapAlloc 函数出故障:
//////////////头文件mem.h/////////////
#pragma once
#include <vector>
#include <algorithm>
#include <assert.h>
#include <windows.h>
#define MAX_OBJ_SZ 64
class chunk;
class FixedAllocator;
class GenAllocator;
template <class T> class Allocator;
class chunk //块表
{
public:
void* allocatebytes(DWORD bksz);//分配bksz大小的块,该bksz必须是初始化时的默认大小,分配不到则返回0
void deallocatebytes(void* pbyte,DWORD bksz);//释放bksz大小的块,同样必须是初始化时的默认大小
void init(int blocksize=4);//创建chunk时直到init才真正分配内存,并初始化
void release();//完全释放内存
char * pData;//256个块的数组指针
char * Head;//链表可用头指针
DWORD Available;//可用数量
};
class FixedAllocator //块表数组
{
public:
void * allocatefixedblock();//分配大小为block_size的块
void deallocatefixedblock(void* pfixed);//释放大小是block_size的块
explicit FixedAllocator(int blocksize);//初始化块表vector,大小存入block_size
~FixedAllocator();
bool isInpool(void* p);//判断p是否在本vector内部
void init(); //在构造后合适的时机初始化内部的第一chunk,以使得迭代器不指空
private:
int block_size;
typedef std::vector<chunk> Chunks;
Chunks chunkstable;
Chunks::iterator pLastAlloc;
Chunks::iterator pLastDealloc;
FixedAllocator();
friend class GenAllocator;
};
class GenAllocator
{
public:
void* allocate(int size);//从内部的FixedAllocator中,找一个符合blocksize的分配块(如没有则创建该FixedAllocator)
void deallocate(void* pblock,int size);//释放大小为blocksize的块
explicit GenAllocator(int bkszauto,int maxblocksize=MAX_OBJ_SZ);//bkszauto:最可能大小,pool_初始化时默认构造第一个Fixed大小
~GenAllocator();
bool Inpool(void* p);//判断p是否在整个缓冲池内,是则真,不是则假
private:
int maxsize;
int autosz;
typedef std::vector<FixedAllocator> MemBk;
MemBk pool_;
MemBk::iterator pLastAllo_;
MemBk::iterator pLastDeallo_;
GenAllocator();
GenAllocator(const GenAllocator&);
GenAllocator& operator=(const GenAllocator& rhs);
};
template <class T=int> //T: 类型名称,用于控制特化
class Allocator //用int型表示未特化的模板
{
static GenAllocator *pAllo;//所有的公用
public:
Allocator(){ pAllo=new GenAllocator(4);}
explicit Allocator(int auto_size,int maxsz=MAX_OBJ_SZ){
pAllo=new GenAllocator(auto_size,maxsz);
};//创建出唯一的GenAllocator,其下属的FixdeGenAllocator规格是auto_size,GenAllocator中至少有一个chunk(不制定规格的话其大小是默认:4bytes)
~Allocator(){ delete pAllo; }
void* allocate(int size)const{
return pAllo->allocate(size);
};
void deallocate(void* pblock,int size)const{
pAllo->deallocate(pblock,size);
};
};
问题点数:100、回复次数:13Top
1 楼nbb()回复于 2003-12-02 22:58:57 得分 0
////////////////实现文件mem.cpp//////////////////
# include "stdafx.h"
#include "memory.h"
#pragma once
GenAllocator* Allocator<int>::pAllo=0;
void chunk::init(int blocksize)//默认的规格是4BYTE
{
assert(blocksize%4==0&&blocksize!=0);
rty:
pData=::new char[256*blocksize];
Available=256;
Head=pData;
register int* p;
register int pnext=(int)pData;//指向块n的头4BYTE
for(int n=0;n<256;++n){
p=(int*)pnext;//p指向每块开始
pnext+=blocksize;//前跳
*p=pnext;//填入n+1块的地址到第n块,使得前一块指向下一块
}
*p=0;//最后一块必须为0
}
void chunk::release(){ delete[] pData;}
void* chunk::allocatebytes(DWORD bksz)
{
assert(Available>0&&Available<=256);
assert((Head-pData)%bksz==0);
--Available;
char * ptep=Head;
Head=reinterpret_cast<char*>(*(int*)(Head));//用Head块的下一块填充Head
assert((Head-pData)%bksz==0);
return ptep;
}
void chunk::deallocatebytes(void* pbyte,DWORD bksz)
{
assert(pbyte!=0&&(((char*)pbyte-pData)%bksz==0) );
assert( ((char*)pbyte-pData)/bksz<=256);
assert(Available<256);
++Available;
char* ptep=Head;//备份
Head=(char*)pbyte;//调整Head指向释放的块头
*(int*)Head=int(ptep);//调整Head的链指针使指向原Head
}
///////////////////////////////////////////////////////
FixedAllocator::FixedAllocator(int blocksize): block_size(blocksize){
chunkstable.push_back( chunk() );//至少有一个chunk
pLastAlloc=chunkstable.begin();
pLastDealloc=pLastAlloc;
pLastAlloc->Available=256;
pLastAlloc->pData=0;
pLastAlloc->Head=0;
}
FixedAllocator::~FixedAllocator(){
for(Chunks::iterator it3=chunkstable.begin();it3!=chunkstable.end();++it3){
if(it3->Available!=256){
char* p1="警告"; char* p2="空间尚在使用,已被强行释放";
::MessageBox(0,p2,p1,MB_OK);
}
it3->release();
}
}
void FixedAllocator::init(){
chunkstable.clear();
pLastAlloc->init(block_size);//chunk分配内存并初始化
}
void* FixedAllocator::allocatefixedblock()
{
assert(pLastAlloc<chunkstable.end());
if(pLastAlloc->Available!=0){//前次使用的块有空,直接分配
return pLastAlloc->allocatebytes(block_size);
}
if((pLastAlloc+1<chunkstable.end())&&(pLastAlloc+1)->Available!=0){//前次使用的块已无空,但下一个有
++pLastAlloc;
return pLastAlloc->allocatebytes(block_size);
}
if((pLastAlloc-1>=chunkstable.begin())&&(pLastAlloc+1)->Available!=0){//上一个有
--pLastAlloc;
return pLastAlloc->allocatebytes(block_size);
}
for(Chunks::iterator it1=chunkstable.begin();it1!=chunkstable.end();++it1){//搜索有空的chunk分配
if(it1->Available!=0){ pLastAlloc=it1;
return it1->allocatebytes(block_size); }
}
chunkstable.push_back( chunk() );//都没空,加新的chunk
pLastAlloc=chunkstable.end()-1;
pLastAlloc->init(block_size);//chunk分配空间(因为无构造函数)
return pLastAlloc->allocatebytes(block_size);
}
void FixedAllocator::deallocatefixedblock(void* pfixed)
{
assert(pLastDealloc<chunkstable.end());
__int64 tp= (char*)pfixed - (pLastDealloc->pData);//试探是否在最后一次返还块(tp是与它的距离)
if( tp>0 && tp<256*block_size ){//是则直接释放
pLastDealloc->deallocatebytes(pfixed,block_size);
return;
}
for(Chunks::iterator it2=chunkstable.begin();it2!=chunkstable.end();++it2){//否则搜寻在哪一块
__int64 tp= (char*)pfixed - it2->pData;
if(tp>0 && tp<256*block_size ){
it2->deallocatebytes(pfixed,block_size);
pLastDealloc=it2;
return;
}
}
char* p1="严重错误"; char* p2="返回的空间不能回收";
int rv=::MessageBox(0,p2,p1,MB_OK);
exit(rv);
}
bool FixedAllocator::isInpool(void* p){
for(Chunks::iterator it=chunkstable.begin();it!=chunkstable.end();++it){
if(it->pData<=(char*)p && (it->pData+256*block_size)>(char*)p ) return 1;
}
return 0;
}
////////////////////////////////////////////////////
GenAllocator::GenAllocator(int bkszauto,int maxblocksize)
: maxsize(maxblocksize),autosz(bkszauto){
pool_.push_back( FixedAllocator(bkszauto) );//至少构造一个,使得迭代器有值
pLastAllo_=pLastDeallo_=pool_.begin();
pLastAllo_->init();//初始化推入vector中的第一个FixedAllocator
}
GenAllocator::~GenAllocator()
{
}
void* GenAllocator::allocate(int size)
{
if(size>maxsize) return ::operator new(size);
size+=3;//4-1
size&=0xfc;//4对齐
if(pLastAllo_->block_size==size){//猜测命中直接分配
return pLastAllo_->allocatefixedblock();
}
for(MemBk::iterator it4=pool_.begin();it4!=pool_.end();++it4){//搜寻,如果已有该大小的分配,接着调整pLastAllo_
if(it4->block_size==size){
pLastAllo_=it4;
return it4->allocatefixedblock();
}
}
pool_.push_back(FixedAllocator(size));//没有找到需要大小的,直接构造
pLastAllo_=pool_.end()-1;
pLastAllo_->block_size=size;
return pLastAllo_->allocatefixedblock();
}
void GenAllocator::deallocate(void* pblock,int size)
{
if(size>maxsize) return ::operator delete(pblock);
size+=3;//4-1
size&=0xfc;//4对齐
if(pLastDeallo_->block_size==size){//猜测命中
pLastAllo_->deallocatefixedblock(pblock);
return;
}
for(MemBk::iterator it4=pool_.begin();it4!=pool_.end();++it4){
if(it4->block_size==size){
it4->deallocatefixedblock(pblock);
pLastDeallo_=it4;
return;
}
}
char* p1="严重错误"; char* p2="返回的空间不能回收";
int rv=::MessageBox(0,p2,p1,MB_OK);
exit(rv);
}
bool GenAllocator::Inpool(void* p){
for(MemBk::iterator it=pool_.begin();it!=pool_.end();++it){
if(it->isInpool(p)) return 1;
}
return 0;
}Top
2 楼nbb()回复于 2003-12-02 22:59:24 得分 0
////////////////程序文件tst.cpp////////////////////
#include "stdafx.h"
#include "memory.h"
using namespace std;
class one{
int ss[32];
};
int _tmain(int argc, _TCHAR* argv[])
{
Allocator<int> alloc1;
one* pone=new one; //这里出故障,可追踪到是API的 HeapAlloc 函数,它是 new 的地层函数
cout<<pone<<endl; //也可能这里失败,同样可追踪到 HeapAlloc 函数出故障,奇怪的是cout能够输出结果
//感觉好像是跟运行库有关? 请高手指点
return 0;
}
Top
3 楼nbb()回复于 2003-12-02 23:06:11 得分 0
编译器是VC71.NETTop
4 楼smalltalk(老徐)回复于 2003-12-02 23:15:52 得分 10
niu biTop
5 楼jyc_nj(老蔣)回复于 2003-12-03 14:02:41 得分 0
不好意思, 请问one* pone=new one;怎样调用到你的函数?Top
6 楼yjh1982(血精灵)回复于 2003-12-03 14:34:51 得分 20
应该是某个在main函数之前的操作引起(如static 变量)Top
7 楼nbb()回复于 2003-12-03 22:30:43 得分 0
“不好意思, 请问one* pone=new one;怎样调用到你的函数?”
那是使用 ::newTop
8 楼jyc_nj(老蔣)回复于 2003-12-04 09:39:12 得分 0
全局的::operator new么?
你在哪里重载了new ? 程序太长;)Top
9 楼nbb()回复于 2003-12-04 13:25:27 得分 0
上面的没给出来:(不过已经可以使得全局的 ::NEW 出异常)
const static AllocGen;
class SmallObj //需要时直接对其继承
{
SmallObj(const SmallObj& rhs);
public:
SmallObj(){}
virtual ~SmallObj(){}
//explicit SmallObj(int auto_size,int maxbksz=MAX_OBJ_SZ);//创建出唯一的GenAllocator,其下属的FixdeGenAllocator规格是bk_size,GenAllocator中至少有一个chunk(不制定规格的话其大小是默认:4bytes)
static void* operator new(size_t size){
return AllocGen.allocate(size);
}
static void operator delete(void* p,size_t size){
AllocGen.deallocate(p,size);
}
};
Top
10 楼jyc_nj(老蔣)回复于 2003-12-04 14:07:23 得分 40
觉得全局的operator new,你既不能重载,还要保证它的调用不会出错(不会被你重复调用)
我觉得显式的分配内存,容易控制.Top
11 楼smaxll(古颜)回复于 2003-12-05 09:42:54 得分 20
关注Top
12 楼holy198048(holy)回复于 2003-12-05 10:27:01 得分 10
关注Top
13 楼nbb()回复于 2003-12-06 18:13:38 得分 0
已经解决,是标准库多处地方需要的默认构造函数和析构函数与上面的某些类有冲突,重新设计了相关的函数后解决Top




