[SoC 2007] Custom Memory Heaps and Object Allocators

Threads related to Google Summer of Code
c4llidus
Gnoblar
Posts: 16
Joined: Fri Apr 13, 2007 9:02 am
Location: Aberystwyth, Wales, UK

Post by c4llidus »

btmorex wrote:
c4llidus wrote:Thanks for the input btmorex,
My understanding of the mechanism of delete is that the version with size_t is implicitly called if it is defined, this is certainly the case with the exaple code I have created. It sounds like your referring to the no-throw version of delete defined as :-

void operator delete(void*, const nothrow_t&) throw();

This indeed needs to be called explicitly as you describe. The overload of single parameter delete works as expected and is employed to direct deallocations to the global allocator presently. The lack of size info is going to be a pain for some allocator types though.
I'm pretty sure you can overload the nothrow versions too. afaik, you can't overload placement versions. For example, this is from the <new> header on my system:

Code: Select all

/** These are replaceable signatures:
 *  - normal single new and delete (no arguments, throw @c bad_alloc on error)
 *  - normal array new and delete (same)
 *  - @c nothrow single new and delete (take a @c nothrow argument, return
 *    @c NULL on error)
 *  - @c nothrow array new and delete (same)
 *
 *  Placement new and delete signatures (take a memory address argument,
 *  does nothing) may not be replaced by a user's program.
*/
void* operator new(std::size_t) throw (std::bad_alloc);
void* operator new[](std::size_t) throw (std::bad_alloc);
void operator delete(void*) throw();
void operator delete[](void*) throw();
void* operator new(std::size_t, const std::nothrow_t&) throw();
void* operator new[](std::size_t, const std::nothrow_t&) throw();
void operator delete(void*, const std::nothrow_t&) throw();
void operator delete[](void*, const std::nothrow_t&) throw();

// Default placement versions of operator new.
inline void* operator new(std::size_t, void* __p) throw() { return __p; }
inline void* operator new[](std::size_t, void* __p) throw() { return __p; }

// Default placement versions of operator delete.
inline void  operator delete  (void*, void*) throw() { }
inline void  operator delete[](void*, void*) throw() { }
Of particular note: "Placement new and delete signatures (take a memory address argument, does nothing) may not be replaced by a user's program."

yes, the placement version of delete can't be overloaded and is only ever called by the compiler in very specific situations, or explicitly. The nothrow versions can be overloaded but they need to be called explicitly afaik.

If defined then the version of delete taking the second std::size_t parameter is invoked via a standard 'delete some_pointer;', the value of the second parameter being generated by the wonderful power of compiler magic, or not in this case :(
- Tim
User avatar
steven
Gnoll
Posts: 657
Joined: Mon Feb 28, 2005 1:53 pm
Location: Australia - Canberra (ex - Switzerland - Geneva)
Contact:

Post by steven »

I hope you DON'T use a heap per thread because I found a bad news.

I was looking how to make my Memory Mgr thread safe.

So I thought TWO seconds and I said to myself I should "use a heap for each thread" ... Seems obvious, no?

I thought about that one year ago but hadn't the time to implement it.

Now after simple google I fall on THAT : http://www.patentstorm.us/patents/7111294.html
A patent issued on sept 06 on "thread-specific heap"

What the f***...
Are the legislators so stupid they can't see what is obvious!

America will fall because of all those legislations.

:evil: :evil:
c4llidus
Gnoblar
Posts: 16
Joined: Fri Apr 13, 2007 9:02 am
Location: Aberystwyth, Wales, UK

Post by c4llidus »

Wow :shock: , thanks for the input, hummm I'll have to give that some brain time, i wander how specific it is. Maybe it wont apply to having a load of small heaps some of which just happen to belong to thread A and some to thread B. I also think that HOARD and maybe Heap Layers both use this technique :?:

I agree with you on the software patent stuff, complete lunacy.
- Tim
User avatar
steven
Gnoll
Posts: 657
Joined: Mon Feb 28, 2005 1:53 pm
Location: Australia - Canberra (ex - Switzerland - Geneva)
Contact:

Post by steven »

@c4llidus Your implementation is very probably different enough that you will not be liable. Microsoft is using some specific ideas (shared memory, threadnew, ...). I didn't see anything about policy btw.

The underlying work seems to be http://www.cs.purdue.edu/homes/hosking/ ... sgaard.pdf

What drives me mad is that I don't have the time to review all the existing patents in the world each time I write a single line of code and verify that I don't breach a patent!
c4llidus
Gnoblar
Posts: 16
Joined: Fri Apr 13, 2007 9:02 am
Location: Aberystwyth, Wales, UK

Post by c4llidus »

@steven Yeah, I agree, I didn't even think of looking for this sort of thing. Im guessing it can be a real easy gotcha :evil:
- Tim
User avatar
Project5
Goblin
Posts: 245
Joined: Mon Nov 22, 2004 11:56 pm
Location: New York, NY, USA

Post by Project5 »

Hoard does use a per thread heap, and if I recall correctly is older than that Patent. You'd need to read it through to check that some of the Hoard guys aren't on the author list though.

--Ben
c4llidus
Gnoblar
Posts: 16
Joined: Fri Apr 13, 2007 9:02 am
Location: Aberystwyth, Wales, UK

Post by c4llidus »

Well I guess GSoC 07 is mostly over now, its been fun :) Of course there is still a lot to do to this project yet and I'm looking forward to continuing work on it and involvement with OGRE :D

@project5 thanks for the confirmation, I have emailed Emery Berger (main author of HOARD) during this project with a few questions, so I'll fire off another mail to get info on this.

Whats been done:
- A main generic memory manager to handle ::new/::delete and to back up specific allocators.
- A small object specific allocator policy
- Thread safe memory profiling framework
- Memory allocator framework
- Inheritable base class for easy use

What needs to be done:
- optimisation to the allocators
- per-thread stuff, see wiki
- plenty of bug fixing im sure ;)
- refactoring of MemProfileManager to make it more robust
- simplification of the interaction between memory profilers and the manager
- hooking up more OGRE objects to use specific allocators, I have tried this with the smallAllocPolicy and SceneNode and Renderable objects

Anyone who would like to give feedback on this would be very welcome, the project is still under heavy development though so expect stuff to change.
- Tim
User avatar
xavier
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 9481
Joined: Fri Feb 18, 2005 2:03 am
Location: Dublin, CA, US
x 22

Post by xavier »

What's the current status on this?
Do you need help? What have you tried?

Image

Angels can fly because they take themselves lightly.
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66
Contact:

Post by sinbad »

I'm chasing Tim up on this, he had said he'd wanted to carry on, but I know he moved house, got engaged and has a fairly busy final year so was giving him a bit of space initially.
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66
Contact:

Post by sinbad »

He's still intending on continuing with it, but has just way too much work on at uni apparantly. Hopefully in the new year, but in the meantime if you want to get involved that's good.
danien
Gnoblar
Posts: 3
Joined: Mon Nov 05, 2007 3:02 pm

Post by danien »

Just a couple of things to add:

1) The delete keyword always calls the single argument version of operator delete. Overloaded operator delete functions are automatically called when the object's constructor throws an exception while using a corresponding operator new with the same argument signature. See http://www.parashift.com/c++-faq-lite/d ... #faq-11.14 (Problem #1)

2) I tried to implement a memory allocator framework that allowed run-time plugin allocators but came across an issue with deferred instantiation of static objects which I'm not sure how to resolve.

Code: Select all

// From FreeImage, TagLib.cpp
TagLib& 
TagLib::instance() {
	static TagLib s;
	return s;
}
Instead of exposing the static instance of TagLib as a global, it was placed inside a global accessor function, allowing it to be created only when the function is first called. While this avoids the issue of un-guaranteed order of initialization of static objects, it also means that construction and destruction order are now harder to "match up".

For example, suppose we have the following:

Code: Select all

// Install our memory allocator at run-time.
oldAllocator = SetMemoryAllocator( myAllocator );
...

// Someone calls TagLib::instance for the very first time.
TagLib::instance(); // This creates the static instance of TagLib using our custom allocator.
...

// Shutting down. Uninstall our custom allocator. Or perhaps someone switches to another allocator.
SetMemoryAllocator( oldAllocator );
...

// Program ends and the C/C++ run-time cleans up, destroying all static objects.
// The static instance of TagLib will now be destructed and its memory freed using the old allocator (or a different one)!!!
Hope someone can come up with a better design that prevents this. In the meantime, I think I'll have to switch back to compile-time determination of allocators.
User avatar
sinbad
OGRE Retired Team Member
OGRE Retired Team Member
Posts: 19269
Joined: Sun Oct 06, 2002 11:19 pm
Location: Guernsey, Channel Islands
x 66
Contact:

Post by sinbad »

You might want to try SVN branch 'v1-6', I've been incorporating a new memory allocator framework there based on a mixture of influences, including last years GSoC work. See this thread.
danien
Gnoblar
Posts: 3
Joined: Mon Nov 05, 2007 3:02 pm

Post by danien »

Thank you. I'll check that out.
Post Reply