• Advertisement
Sign in to follow this  

C++ custom memory manager ideas

This topic is 3625 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

as many articles have pointed out, using the heap can lead to memory fragmentation, memory leaks and can often be slow when allocating / deallocating lots of objects constantly. To fix that, there are some pretty creative memory manager solutions out there, such as smart pointers and what not. I was looking at Enginuity's tutorial on a memory manager, and if I understand it correctly, it essentially allows you to keep track of your memory really well, and do garbage collection simply. It solves the problem of loosing track of your memory, but it doesn't solve the fragmenting issue; we only store pointers to the data which is directly stored on the heap. The implementation i'm curious about is essentially the following: overload the new and delete operators to go and fetch from a static container which is pre-allocated with some N+1 number of objects of that type (the container can be defined in teh base class much like Enginuity's design). The size of a block is the size of whatever the largest derived object will be. so, if the objects are A and B, where B is a child of A and sizeof(B) = 16 and sizeof(A) = 4, then the container would have blocks of size 16 lets forget about the fact that this design has bounds on the memory that need to be known upfront, along with a hefty allocation fee if you've got a lot of objects being created... my problem is, how do I get the containers blocks to a) be dynamically sizeable AND b)take in any object of that class, along as it is a "family member." so, i should be able to call new on A or B, and get the proper, pre-allocated space for it. Any ideas if this is possible, or even done?? I hope that makes sense?

Share this post


Link to post
Share on other sites
Advertisement
Ah, the joys of non-GC languages [smile]

Quote:
my problem is, how do I get the containers blocks to a) be dynamically sizeable


Something equivalent in functionality to:
template <size_t size>
class memory
{
typedef std::list<boost::array<char, size> > buffer;
};


Then, dispatch to the correct buffer based on the size of the block you are currently allocating or deallocating.

Quote:
AND b)take in any object of that class, along as it is a "family member."


Overloading operator new and delete in your hierarchyshould achieve this.

Share this post


Link to post
Share on other sites
Sounds like you mean a pooled allocator, something like Boost.Pool. Normally you only have the pool store one type of object or you store all objects of a single size in a single pool rather then using a single pool for all objects derived from a certain object. Your setup also causes problems when allocating an array since you have to return a block of contiguous memory, whereas the above wouldn't be contiguous when allocating an array of A. You could overcome that by using a separate mechanism for arrays but you really are better of grouping them by size instead of base class.

A simple [and incomplete] implementation of the size based one might look something like this.

template<std::size_t N>
struct sized_allocator
{
static std::vector<bool> allocated;
static std::vector<char> memory;

static void* allocate()
{
for (std::size_t i = 0; i < allocated.length(); ++i)
{
if (allocated)
{
return reinterpret_cast<void*>(&memory[i * N]);
}
}
}

static void deallocate(void* obj)
{
std::ptrdiff_t offset = obj - memory;
std::size_t i = static_cast<std::size_t>(offset) / N;
allocated = false;
}
};

template<typename T>
struct allocator : sized_allocator<sizeof(T)>
{
typedef sized_allocator<sizeof(T)> base_t;

static T* allocate() { return reinterpret_cast<T*>(base_t::allocate()); }
static void deallocate(T* loc) { base_t::deallocate(reinterpret_cast<void*>(loc)); }

static void construct(T* loc, T& cpy) { new(loc) T(cpy); }
static void deconstruct(T* loc) { loc->~T(); }
};

Share this post


Link to post
Share on other sites
Quote:
Original post by RandomAxess

my problem is, how do I get the containers blocks to a) be dynamically sizeable


This requirement alone is difficult enough. You can't have a cake and eat it too.

Allocate block large enough for N elements. Allocate from there. If the block is exhausted, allocate another block just like this. Repeat as needed.

Quote:
AND b)take in any object of that class, along as it is a "family member."
so, i should be able to call new on A or B, and get the proper, pre-allocated space for it. Any ideas if this is possible, or even done??



Yes, it's possible. You implementation will have exactly the same characteristics as "operator new".

Pre-allocated memory is just that. You pre-allocate a known or anticipated size of memory.

Quote:
overload the new and delete operators to go and fetch from a static container


I dislike overloading global new/delete operators. For one, it messes with existing libraries and causes problems with DLLs and third-party libraries. Secondly - it's not thread-safe, and worst of all, you lose control over track-safety, meaning you need to lock on every single allocation.

STL containers give you the option of an allocator. For your own objects, you can provide similar functionality. That alone is enough to solve the fragmentation problems.

Quote:
if the objects are A and B, where B is a child of A and sizeof(B) = 16 and sizeof(A) = 4, then the container would have blocks of size 16


You better ensure alignment as well. In this case, going with two different allocators is considerably better choice.

The reason why such custom allocators are "better" than generic new is because they're specific and fully aware of the types they'll allocate. And in order to deal with multiple types you need to implement so much logic, that it's simply not worth it.

Share this post


Link to post
Share on other sites
Thanks for everyone's replies, I appreciate it. I'll look into allocators rather than overloaded new and delete.

Let me ask a better question then, Since Boost already has a memory pool, what benefit would I really get from re-creating one? Should I just use Boost's memory pools, and create one pool per object type before the game starts up, and just use that for all memory activities?

Share this post


Link to post
Share on other sites
Quote:
Original post by RandomAxess
Let me ask a better question then, Since Boost already has a memory pool, what benefit would I really get from re-creating one? Should I just use Boost's memory pools, and create one pool per object type before the game starts up, and just use that for all memory activities?

Well that depends, what problem are you trying to solve?

(Hint: You don't know. Because all you've done is read "oh ten noes! allocation causes fragmentation and is teh slows!!1". You have to know what your problem is before you can solve it. Profile first (both speed and memory use), see what your current situation actually is, and determine which specific areas (if any) need to be improved. Then you'll be able to make an informed decision rather than blindly stabbing in the dark).

Share this post


Link to post
Share on other sites
OrangyTangy>
Thanks for the reply. True, most of my interest in the question comes from having heard and read about the trouble with memory leakage, and that building a custome memory manager is best (or using a good pre-existing one).

A lot of this comes from sheer curiosity as well, not neccesarily because "I need one right now," but I'd like to come with a decent design for one, maybe create it / use it and see how it works.

Share this post


Link to post
Share on other sites
Quote:
Original post by RandomAxess
OrangyTangy>
Thanks for the reply. True, most of my interest in the question comes from having heard and read about the trouble with memory leakage, and that building a custome memory manager is best (or using a good pre-existing one).

A lot of this comes from sheer curiosity as well, not neccesarily because "I need one right now," but I'd like to come with a decent design for one, maybe create it / use it and see how it works.


Well, then you just answered your own question.
Yes, you should write one yourself, rather than use Boost's pool allocator. Because as you just said, the goal is to satisfy your curiosity.

Share this post


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

  • Advertisement