April Fools! Damnable Memory Management.

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

Recommended Posts

Okay, so I had implemented Richard Fine (a la Enginuity)'s system of memory management. All was fine until my ModelMD2 class had to inherit from the Model class and the Animation class, both of which inherited from my equivalent of the CMMObject. Compiler error, no problems knowing what the problem was, but rejigging it was a little annoying. So anyway, the little problem said hello again today, and fed up with it, I decided to take another route. So I wrote a crazy little thing that was basically a bastardization of the Factory Pattern (I assume it is, I barely know what the factory pattern is, so it must be). It tracks all instances of T created by it and deletes all of them at the end of execution (unless the programmer removes an object during runtime). It's still work in progress, so don't judge too hard (although hints would be nice!). Then, about two hours ago, I find out about virtual inheritence. Now I'll be damned if I wasn't slapped in the face by that. It solves all my problems just like that. However, I kind of like this new factory thing, and I know that it's going to be pretty fast and smooth. I know less about virtual inheritence, and I know that smart pointers have overhead. So I was wondering: A) Which do you think would suit better? B) What are you using for memory management? I mean, at the very best, someone could put me on the right direction. I've already done a lot of reading, but there doesn't seem to be a consensus when it comes to certain (regular) situations. - Cheers

Share on other sites
Okay, I gotta know: Are these objects doing stuff in their dtor that doesn't have to do with memory? Like say, writing to a file or the registry? Because if not, there's no point in tracking objects until the death of the program: the OS will reclaim your app's memory when your app dies (by quitting or crashing or any other way).

Smart pointers, on the other hand, keep track of an object until they aren't used, then deletes them. This means that while your app is running it is using exactly as much memory as it needs (with a small overhead). Your method will make the app use far more memory than it needs because it waits until the end of the program to clean it up, and then immediately afterward the OS does the same thing. Basically, you still leak memory, but your destructors WILL be called before the application quits. In some instances this is necessary (like if you're writing to a file, the registry, sending a message to another app, that sort of external data modification), but in most it isn't, and even if it were, fixing the leaks will still make sure the dtor is called. Now you could convert this factory into a leak detector by making note of where objects are created, and when they're deleted by the factory let you know that this was necessary, but on its own this factory won't fix leaks.

As for "what I use", it depends. Right now I'm mostly using .Net's garbage collection. When I'm writing in native C++ I use boost::smart_pointer and boost::weak_ptr.

Share on other sites
When using a system like the CMMObject system, how does one prevent multiple instances of CMMObjects pointing to the same resource thus creating separate reference counts?

Share on other sites
My first three incarnations of a memory manager used smart pointers and reference counting. However, for the record, those versions sucked. Mainly because I don't like smart pointers, and I feel that they are a pain to work with. I want to have control of when my objects are deleted, sometimes you need it. So now, I have a memory manager with an Alloc/Delete system, but which tracks leaks, usage, etc. That way while it doesn't fix all my problems for me (in an inferior, general sort of way), it tells me where the problems are, and allows me to fix them in a superior, exact sort of way.

There's still an overhead, since I use Pointer objects. While they're not smart, they're still necessary, to allow me to defragment the memory heap while running asynchronously. And do some other cool stuff.

Anyway, in reality, I haven't implemented half of that, but it's all designed, and the foundations are all in place. I just have to brace my self and take the plunge one day, and finish it.

Share on other sites
Quote:
 Original post by smrWhen using a system like the CMMObject system, how does one prevent multiple instances of CMMObjects pointing to the same resource thus creating separate reference counts?

The only time this can happen in Enginuity (that I can think of) is with multiple inheritance, in which case you use virtual inheritance, which is another can of worms entirely.

If you use boost's smart pointers instead of enginuity's intrusive pointers, you have to copy the smart pointer, not the dumb pointer.
int main(){    boost::shared_ptr<int> i = new int(5);    //Do NOT do this:    int* ptr = i.get();    boost::shared_ptr<int> e(ptr);//e and i use different ref counts now, so multiple deletes.    //Do this:    boost::shared_ptr<int> b(i);//b and i use same ref count, so only one delete.}

Note that the smart pointers don't force any change in the class. Enginuity requires you to derive off of the IMMObject class, which then causes multiple inheritence issue.

Share on other sites
Yes, but what exactly is the can of worms? According to the C++ FAQ, all I have to really worry about is calling the virtual base's constructor in the initialisation list of the classes I derive from. And considering IMMObject doesn't have parameters in its constructor, it's barely a problem in that respect.

And I very well may jig my factory class to track object's lifetimes. I was thinking, if I used a hash_map (eventually, TR1 and waiting) inside the factory class, then whenever my smart pointer was given a reference from a normal pointer, I could quickly get the correct reference count for that object. Like:

// in AFactory<T>static std::map<T*, int*> mReferenceMap;static int * getReference(T * object){	// if this object's address hasn't been tracked before,	// it now has one reference. It SHOULD be tracked before.	if (!mReferenceMap.count(object))		mReferenceMap[object] = new int(1);	return mReferenceMap[object];}// in class APointer<T>int * mReferences;APointer(T * object){	// get references to pointer	mReferences = AFactory<T>::getReference();	(*mReferences)++;}

And then the smart pointer acts like any other. That way even with bad coding, like saying

APointer<CDuck> duck = AFactory<CDuck>::create()CDuck * duck2 = duck2;APointer<CDuck> duck3 = duck2;

Theoretically (and I've been programming in this repost box), now duck3 and duck point to the same thing, with the reference count of 2. I don't know, my mind just kind of wandered onto this whilst I was replying, so I decided to run with it. Hope it helps.

• What is your GameDev Story?

In 2019 we are celebrating 20 years of GameDev.net! Share your GameDev Story with us.

• 11
• 15
• 11
• 11
• 9
• Forum Statistics

• Total Topics
634150
• Total Posts
3015827
×