void MemoryManager::Create(void) {
m_LiveObjects.clear();
m_DeadObjects.clear();
m_lTopHash = 0;
m_lHeapAllocSize = 0;
}
void MemoryManager::Destroy(void) {
// this is a direct-kill; nothing in between ;)
m_LiveObjects.Release();
m_DeadObjects.Release();
#ifdef _DEBUG
if(m_lHeapAllocSize > 0)
SysMem(__FUNCTION__,"Heap allocation size is wrong; %d",m_lHeapAllocSize);
SysMem(__FUNCTION__,"Total memory objects this run %d",m_lTopHash-1);
#endif
m_LiveObjects.clear();
m_DeadObjects.clear();
}
void MemoryManager::KillObject(ulong lHash) {
// when this is called; we're moving an object from the "live" list to
// the "dead" list. So we need to check to make sure it's here first!
if(m_LiveObjects[lHash] != NULL) {
IMemoryObject* p = m_LiveObjects[lHash];
// make sure to get rid of her
m_LiveObjects.remove(p);
// houston - we have a problem!
if(m_DeadObjects[lHash] != NULL) {
// assign the object a new hash id
p->m_lHashID = NextHashID();
#ifdef _DEBUG
SysMem(__FUNCTION__,"Memory object with hash %d already exists on dead list; reassigning hash to %d",
lHash,p->m_lHashID);
#endif
}
m_DeadObjects[p->m_lHashID] = p;
// flag the object as killed incase we need to bring it back onto the live list
p->m_bKilled = true;
#ifdef _DEBUG
SysMem(__FUNCTION__,"Memory object moved to dead list; %d",p->m_lHashID);
#endif
return;
}
SysWarn(__FUNCTION__,"Memory object with hash %d does not exist",lHash);
return;
}
//j: this is how we're going to allocate blocks of memory; this placed in the
//"" overloaded "new" operators of all devrived IMemoryObject objects
IMemoryObject* MemoryManager::AllocBlock(size_t size) {
IMemoryObject* p = (IMemoryObject*)malloc(size);
*p = IMemoryObject(); // invoke the constructor
m_lHeapAllocSize += static_cast<ulong> (size);
#ifdef _DEBUG
SysMem(__FUNCTION__,"Memory block allocated with a size of %d",size);
#endif
return p;
}
//j: deallocation of memory blocks (otherwise 'freeing')
void MemoryManager::DeallocBlock(IMemoryObject* p) {
m_lHeapAllocSize -= p->m_lAllocSize;
free(p);
#ifdef _DEBUG
SysMem(__FUNCTION__,"Memory block deallocated with size of %d; heap %d",p->m_lAllocSize,m_lHeapAllocSize);
#endif
}
//j: the good ole 'collect garbage' function; woo
void MemoryManager::CollectGarbage(void) {
for(CMemoryMap::iterator it=m_DeadObjects.begin();
it != m_DeadObjects.end(); it++) {
IMemoryObject* p = it->second; // store pointer
it = m_DeadObjects.remove( it ); // remove from list
DeallocBlock( p ); // deallocate
}
m_DeadObjects.clear(); // start fresh
}
void MemoryManager::AddObject(IMemoryObject* p) {
if(m_LiveObjects[p->m_lHashID] != NULL) {
SysWarn(__FUNCTION__,"Memory object with hash %d already in live list",p->m_lHashID);
p->m_lHashID = NextHashID();
}
m_LiveObjects[p->m_lHashID] = p;
#ifdef _DEBUG
SysMem(__FUNCTION__,"Memory block with hash %d added to live list",p->m_lHashID);
#endif
}
IMemoryObject::IMemoryObject(void) {
MemoryManager mem;
m_lAllocSize=sizeof(*this);
m_lHashID=mem.NextHashID();
m_bKilled=false;
mem.AddObject( this );
}
//j: overload the new operator with the memory manager's allocation method
void* IMemoryObject::operator new(size_t size) {
MemoryManager mem;
return ( mem.AllocBlock(size) );
}
//j: overload the delete operator with the memory manager's deallocation method
void IMemoryObject::operator delete(void* p) {
MemoryManager mem;
mem.KillObject( ((IMemoryObject*)p)->m_lHashID );
}
//j: I have decided to make the Memory Manager a Monostate instead of a
//"" singleton; this can always be changed in the future if deemed needed
class MemoryManager : public IMonoState {
public:
MemoryManager(void) { }
~MemoryManager(void) { }
static void Create(void);
static void Destroy(void);
void KillObject(ulong);
void AddObject(IMemoryObject*);
IMemoryObject* AllocBlock(size_t);
void DeallocBlock(IMemoryObject*);
IMemoryObject* ReallocBlock(IMemoryObject*,size_t);
void CollectGarbage(void);
inline ulong NextHashID(void) const { return m_lTopHash++; }
private:
//j: we're going to have our hash map an extension of std::map
class CMemoryMap : public map_t<ulong,IMemoryObject*> {
public:
// physically dump all of the objects onto the garbage collector
inline void Release(void) {
MemoryManager mem;
for(iterator it=begin(); it != end(); it++)
mem.DeallocBlock( it->second );
clear();
}
// I don't know why the STL doesn't return the previous iterator;
// but it just sticks me off when I need to create another instance
// just to delete a damn object ; so here we are
inline iterator remove( iterator it ) {
iterator i = it--;
erase( i );
return it;
}
// if we want to remove something by having a pointer of the obj
inline iterator remove( IMemoryObject* p ) {
ulong hash=p->GetHash();
for(iterator it=begin(); it != end(); it++) {
if(hash==it->first) {
if(p==it->second) {
it=remove(it);
return it;
}
}
}
return NULL;
}
};
static CMemoryMap m_LiveObjects;
static CMemoryMap m_DeadObjects;
static ulong m_lTopHash;
static ulong m_lHeapAllocSize;
};
//j: this is the base memory object that can be devrived from anything
//"" that we wish to utilize the memory manager interface
class IMemoryObject {
friend class MemoryManager;
public:
IMemoryObject(void);
virtual ~IMemoryObject(void) { }
void* operator new(size_t);
void operator delete(void*);
virtual void Release(void);
// this is how we deal with objects in the DeadObjects list
inline bool IsKilled(void) const { return m_bKilled; }
inline ulong GetHash(void) const { return m_lHashID; }
private:
ulong m_lAllocSize;
ulong m_lHashID;
bool m_bKilled;
};