Jump to content
  • Advertisement
Sign in to follow this  
sp00n

Memory Manager Woes

This topic is 4904 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm currently writing the memory manager for my latest engine, and i'm coming across somebehaviour that i can't explain. The manager is loosely based upon the Enginuity manager, but I've split it into 2 classes since i think it makes sense more conceptually this way, and is more in line with my way of thinking. I have 2 classes involved, cMemoryMgr, the memory manager class,which is a singleton, and MMObject, which is (obviously) a container / reference counter for the objects to be managed, and serves as a base class from which any objects to be managed are derived. When an MMObject is dynamically created, its overrided new operator passes a pointer to the manager class, which adds this to a list of heap object pointers (via the managers "addtoheap" method) ,before returning this pointer to whatever called new. Then, when MMObjects constructor is called, it calls the managers "add" method, passing a pointer to itself. The add method of the manager checks to see if this pointer is in the list of heap objects, hence determining if the MMObject is on the heap or the stack. If it finds the pointer in the list, the manager removes the pointer from the heapObjects list, and adds it to the deadObjects list (it is added to deadobjects so that unless it is reference count is incremented, it is deleted by a garbage collector at the end of the frame.) My problem is, when the manager searches the heapObjects list in the add method, it never finds an object, even if the object was created on the stack. Debugging shows that the address of the pointer stored in the heapObjects list differs by 4 bytes from the address passed by the MMObject this pointer to the managers add method. Why is this happening? anybody have any idea how to sort this? i'm tearing my hair out! Here are the salient points of the two classes:
class MMObject
{
private:
	long	refCount;
	list<MMObject *>::iterator	location;

public:
	bool	bIsStackAllocated;
		MMObject();
		~MMObject();
	void	AddRef();
	void	Release();
	bool	Referenced();
	void*	operator new(size_t size);
	void	operator delete(void* obj);
};

class cMemoryMgr : public cSingleton<cMemoryMgr>
{
private:
	list<MMObject *> liveObjects;
	list<MMObject *> deadObjects;
	list<MMObject *> heapObjects;
public:
	cMemoryMgr();
	~cMemoryMgr();
	void		CollectGarbage();
	void		CollectRemainingObjects(bool bEmitWarnings=true);
	void		Add(MMObject* obj);
	void		AddToHeap(MMObject* obj);
	void		MoveToLive(MMObject* obj);
	void		MoveToDead(MMObject* obj);
};

MMObject::MMObject()
{
	refCount=0;
	g_cMemoryMgr.Add(this);
}

void MMObject::AddRef()
{
	++refCount;
	if( !bIsStackAllocated && refCount==1 )
		g_cMemoryMgr.MoveToLive(this);
}

void MMObject::Release()
{
	--refCount;
	if( !bIsStackAllocated && refCount<=0 )
		g_cMemoryMgr.MoveToDead(this);
}

void* MMObject::operator new(size_t objsize)
{
	void *newObj=malloc(objsize);
	g_cMemoryMgr.AddToHeap((MMObject*)newObj);
	return newObj;
}

void MMObject::operator delete(void* obj)
{
	if(!((MMObject*)obj)->bIsStackAllocated)
		free(obj);
}


void cMemoryMgr::Add(MMObject* obj)
{
	list<MMObject*>::iterator it = find(heapObjects.begin(), heapObjects.end(), obj);

	if(it==heapObjects.end())
	{
		obj->bIsStackAllocated=true;
	}
	else
	{
		obj->bIsStackAllocated=false;
		deadObjects.push_back(obj);
		heapObjects.remove(obj);
	}
}

void cMemoryMgr::AddToHeap(MMObject* obj)
{
	heapObjects.push_back(obj);
}

void cMemoryMgr::MoveToLive(MMObject* obj)
{
	liveObjects.push_back(obj);
	deadObjects.remove(obj);
}

Thanks in advance o-- spoon --0

Share this post


Link to post
Share on other sites
Advertisement
This might not help much, but the only time I've ever encountered something like that was when I was returning a derived class' pointer rather than the base class' pointer.

Like if your MMObject was derived from another object, the casting wouldn't work right to/from void under certain conditions [which I don't remember clearly...] unless you used the base class' pointer.

Share this post


Link to post
Share on other sites
yeah so if you have multiple inheritence this can happen. So take this class:

class Dog: public animal, public hasPhysics

if you pass the Dog to the physics system as a hasPhysice object the pointer will be offset by the size of the Animal class. if you later get that back as a void* and cast it to Dog you will be off on memory:

it looks roughly like this in memory

class Dog
|
->| Animal
| contents of animal
|
->| HasPhysics
| contents of HasPhysics
|
| contents of Dog


the first -> is where a Dog* or an Animal* point to. the second -> is where a HasPhysics* points to. So you can see that the value of the HasPhysics* does NOT equal the valuse of the Animal* or the Dog*. Thus going: HasPhysics -> void* -> Dog will always break because you will have what you thing is a Dog* but it will be pointing to the wrong part of memory.

The point is that using a base class pointer of a Multiply Inherited Object and a void* is very very bad unless that base class pointer is a pointer to the first base class listed in the object declaration. I believe that using dynamic_cast will take care of this problem. also, not using void* will also help. The solution that we used was to pre-cast the HasPhysics* to a Dog* before casting it to a void*. It is only by going through a void* that the mechanics get confused and you end up pointing to the wrong part of memory.

-me

Share this post


Link to post
Share on other sites
Thanks for the input guys. MMObject is not derived from anything else,but does function as a base class for any memory managed objects. The new and delete operators must work with void pointers, VC8 throws an error otherwise, so there is no way of avoiding some kind of cast from *void to *MMObject.

How would i do this using dynamic_cast?

o-- spoon --o

Share this post


Link to post
Share on other sites
You might want to look into the thread from the article you got that from (I believe it's Engunity?) I think they have a several fixes for the memory manager there that Superpig commented on and they only made it in the final version of the code (which is up there on the last tutorial). There might even be some that haven't made it in, if I remember correctly, this was one of the problems with it.

Having used the above manager, I wrote my own that is a bit like it but uses more princples from the Fluid Studio's manager that everyone seems to love. But it deals with overloading the operators of a single object that is devrived (just like you would with MMObject). I haven't tested it with multiple inheritance yet; but I'm attempting to stay away from that as much as possible.

I'm just a DIY type of person.

Share this post


Link to post
Share on other sites
I've cross-referenced my MM with that of the source in the finalpart of enginuity, and I may be wrong but I've implemented it in pretty much the same way save for splitting it into a manager and an object class. Having liberally sprinkled a few logging statements, i've found the following out:

here is an example to demonstrate. cGlobalTimer is decended from ITask, in turn descended from MMObject.

MMPointer<cGlobalTimer> globalTimer = new cGlobalTimer();

when this is executed, new calls malloc, adding the returned pointer to the MM's heapObjects list, before returning that same pointer. Then the ctor for MMObject is called, but the this pointer for MMObject is 28 bytes higher than the original pointer returned by malloc. The ctor for MMObject then calls the MM's add method, which searches its heapObjects list for the passed pointer, which it obviously won't find since it now differs by 28! Then the constructor for the object being created, the one derived from MMObject, is called (in the above example,the cGlobalTimer ctor). but now the this pointer is the same as the original!
I know why this happens and why it is necessary (if you dont, see Palidines useful explanation above), but I cant see a way to fix my MM so that it works (without using the horrible kludge of manually adding 28 to the pointer before checking it in heapobjects). Could someone show me how i need to alter the code to do this? Thanx!

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!