Advertisement

Comment on wrapper for memory management functions

Started by October 30, 2016 07:28 PM
10 comments, last by Alberth 8 years ago

Hello all

I want to have some basic control over memory allocation in my game engine. I use the classes IAllocatable and MemoryManager.

All classes in the engine derive from IAllocatable. Whenever objects of these classes are instantiated, they automatically call the MemoryManager which in turns calls the standard C/C++ memory functions. Does this make sense? Am I doing something wrong? Any pitfalls I should watch out for?


#ifndef IAllocatable_H
#define IAllocatable_H
 
class IAllocatable
{
public:
void* operator new(std::size_t sz);
void operator delete(void* ptr);
};
 
#endif



#include "IAllocatable.h"
 
void* IAllocatable::operator new( std::size_t sz )
{
return MemoryManager::malloc(sz);
}
 
void IAllocatable::operator delete( void* ptr )
{
MemoryManager::free(ptr);
}



#ifndef MemoryManager_H
#define MemoryManager_H
 
class MemoryManager
{
public:
void* malloc( std::size_t sz );
void free( void* ptr );
};
 
#endif

#include "MemoryManager.h"


void* MemoryManager::malloc( std::size_t sz )
{
return std::malloc(sz);
}
 
void MemoryManager::free( void* ptr )
{
std::free(ptr);
}

Don't reinvent the wheel; there are far superior memory logging systems out there. Is this for a learning exercise of some sort? If not, and you're looking for a memory leak there are tools for that, Windows has the CRT memory logging systems, dmalloc should work too. Instead using modern C++ programming practices like, naked pointers where they're best suited and smart/unique/weak pointers else where, can go a long way to make your code a lot better (when used correctly).

See Hodgman's post and the associated links here about when/how to use them:

http://www.gamedev.net/topic/683462-refering-to-unique-pointers-content/

Otherwise see:

http://dmalloc.com/

But seriously, every class that needs to allocate something needs to derive from your alloc class sounds like a recompiling nightmare if you make even a slight change to it. YMMV.

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

Advertisement

Hello all I want to have some basic control over memory allocation in my game engine. I use the classes IAllocatable and MemoryManager. All classes in the engine derive from IAllocatable.

Aside from making new wheels, how is adding a pass-through layer giving you any control that you didn't already have?

What kind of control are you looking for?

If a Foo class needs control, how do you do that?
If a Bar class needs different control, how do you do that?

I suspect that in the end it's simpler to add custom new/delete operators to those classes that need it.

I'm afraid of the diamond of death here. (In response to "Any pitfalls I should watch out for?".)

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

All classes in the engine derive from IAllocatable.

That's a PITA. Why not just override the global operator new / operator delete?

I did something like this in my engine too and added an assert into the destructor of each allocator for finding memory leaks so any unfreed memory will cause the program to stop working for debug.

Your approach overriding new/delete may be unfavorable because they are called implicitely, instead you should force your objects and classes to use a reference to IAllocater whenever needed. STL objects could also be allocated using custom allocater or skip them completely and make your own string, vector, array and so on ;)

You might find this article interesting describing the theroem of what I use even if my implementation is more different from his one

http://bitsquid.blogspot.de/2010/09/custom-memory-allocation-in-c.html

Advertisement

At the very least, class MemoryManager could secure a big chunk of memory from the heap at start-up, then allocate memory from said chunk instead of going to the C++ runtime everytime. Doesn't that make sense?

I have access to the PhyreEngine code and they are doing something similar (can't be any more specific or post code because that stuff is proprietary).

Allocating from a big chunk makes sense. Doing it via a shared base class, not necessarily. PhyreEngine has to co-exist with a developer's existing libraries and so a global redefinition of new/delete is far from ideal, which basically forces them to implement it that way.

It's also only worth doing if you have a good reason to suspect you can do things more effectively than both the user of your engine and the platform defaults. In Sony's case, they control both the engine and the platform so there's a good chance that they can write something that is tightly integrated and close to optimal. In your case, it's hard to see how you would improve over the standard new/malloc system by default, and since you don't own a platform (I assume) it makes more sense to use a 3rd party system for logging.

Am I correct in thinking you are trying to come up with a solution to manually instrument your code to detect memory leaks? If so you might want to look at using tools like Valgrind (valgrind.org). If your code can only run on Windows then you might have luck with Dr Memory (www.drmemory.org) or IBM Purify (Hard to get hold of these days).

These tools can track down just leaks (in which case they are actually pretty fast) or they can be used to track down stack and heap errors too which is useful.

There is also a library called electric fence that you can link against and it adds canaries to malloc'ed memory so that if it is written to, it segfaults. Quite useful for heap debugging.

Another solution could be using boehms gc to do the allocations. This can be setup to tell you if your code would leak memory even if you are not using the actual GC functionality.

Other than that, smart pointers can solve most issues.

http://tinyurl.com/shewonyay - Thanks so much for those who voted on my GF's Competition Cosplay Entry for Cosplayzine. She won! I owe you all beers :)

Mutiny - Open-source C++ Unity re-implementation.
Defile of Eden 2 - FreeBSD and OpenBSD binaries of our latest game.

At the very least, class MemoryManager could secure a big chunk of memory from the heap at start-up, then allocate memory from said chunk instead of going to the C++ runtime everytime. Doesn't that make sense?

So you're duplicating the functionality of the standard memory manager as well?
Likely your implementation is less good, as malloc & friends are quite old and well developed, I would assume.

I have access to the PhyreEngine code and they are doing something similar

There are also people using Brainfuck, does that mean you should add it too?

My point is that you should think what you want to achieve, and design for that goal. Adding stuff because "someone else did it too" doesn't generally work, as others have different, and possibly even conflicting goals with you.

So decide what you want to achieve with the memory manager, decide what you want to achieve with the big blob of memory. then design that part with the goal in mind.

If you don't know, your best option is usually not add anything until you find out what you actually need.
If you add the wrong solution now, you'll have to remove it again later, which is twice work, without gaining anything.

This topic is closed to new replies.

Advertisement