 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Nick C Guest
|
Posted: Fri Dec 16, 2005 1:44 pm Post subject: Limitation of C++ new & delete? Please prove me wrong |
|
|
I think I have found a bit of a limitation of the C++ language. Hopefully I
will be rigorously corrected with glorious solutions to my problem. I'll try
to be as concise as possible....
The problem is I want a strategy to allow various memory-allocation
strategies to be applied. This would be useful for the following reasons:
1) I may want various allocations from various areas of my design to be
identified to allow diagnostics of memory usage.
2) I may want to apply different allocation strategies based on usage (e.g
normal heap for bitmaps, pool-based system for messages etc..)
I designed a memory system that uses different allocation strategies and
requestor-diagnosics etc. The only remaining issue was how to roll out the
system to the code. I am, in generael, in favour of using the built-in
facilities of a languge and wanted to use/overried 'new' and 'delete' to
access this new system.
The answer you would think is 'placement new'. Yep! I thought so too. By
creating a placement new, I can pass a parameter to 'operator new'. This
parameter was an id that would tell my design which allocation stategy to
use and to allow diagnostics to be logged. All great so far! The trouble was
with 'delete'. If are still reading, then you'll probably know that there is
no equivalent 'placement delete' that can take and extra parameter.
Therefore my system has no way to know which de-allocation strategy to apply
(and makes the diagnostics meaningless). The only options are to do things
like, heap mangagement - i.e when allocaing, and an extra bit of info to
enable the de-allocate to work out what to do. Trouble is this means invalid
'delete' cause exceptions! Also, and extra 4-bytes per allocation is a big
overhead for small allocations.
The only other option to identify deletes is a free-list, but this is too
slow (and also has the overhead).
Other solutions I have looked at are
1) class-based new and delete - overriding new nad delete on all classes
would work, but would then stop new/delete being overriden for any other
purpose. Also a single class (or hierachy) cna only use one memory
management strategy.
2) calling the destructor explicitly. This soes actually work pretty well, I
can create a MACRO that specifies the type and I call the destructor
explicitly, then call 'operator delete' manually to free the memory. Trouble
is this s clunky at best.
What I really want is a placement-delete, and I can't understand why there
isn't one! To summarise, I can't take the performance hit on using the
natural syntax '(placement) new', but also do not wnat to enforce system
wide memory allocation routines that are used in favour of new/delete.
Comments very gratefully received.
Nick Church
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Thomas Richter Guest
|
Posted: Fri Dec 16, 2005 4:47 pm Post subject: Re: Limitation of C++ new & delete? Please prove me wrong |
|
|
Hi,
| Quote: | The problem is I want a strategy to allow various memory-allocation
strategies to be applied. This would be useful for the following reasons:
1) I may want various allocations from various areas of my design to be
identified to allow diagnostics of memory usage.
2) I may want to apply different allocation strategies based on usage (e.g
normal heap for bitmaps, pool-based system for messages etc..)
The answer you would think is 'placement new'. Yep! I thought so too. By
creating a placement new, I can pass a parameter to 'operator new'. This
parameter was an id that would tell my design which allocation stategy to
use and to allow diagnostics to be logged. All great so far! The trouble was
with 'delete'. If are still reading, then you'll probably know that there is
no equivalent 'placement delete' that can take and extra parameter.
Therefore my system has no way to know which de-allocation strategy to apply
(and makes the diagnostics meaningless).
|
Right, so you have to give this information to the system. The usual
approach one takes here is to put this information right into the allocated
memory, as you state below. Allocating an additional chunk of four bytes is,
however, often not enough. Some data has to be aligned to certain
byte-boundaries for some systems, thus you not only need a 4 byte overhead,
you need an "n" byte overhead where "n" is the alignment restriction by
the most-restricted type. Typically "n" has values from one to sixteen,
also depending on the speed penalties one is willing to pay.
| Quote: | The only options are to do things
like, heap mangagement - i.e when allocaing, and an extra bit of info to
enable the de-allocate to work out what to do. Trouble is this means invalid
'delete' cause exceptions! Also, and extra 4-bytes per allocation is a big
overhead for small allocations.
|
Even *if* the operator delete could give you the information about
the memory pool the memory was taken from, it would need to keep this
information somehow. Question is: Where? If the delete is not class specific
and thus not implied by the calling object (thus, no class specific delete,
as you don't want that approach either) it must be kept right in the memory
that has been allocated. Short version: There's no way around this overhead,
it's only that C++ doesn't make this very pretty, or a very accessible
technique.
| Quote: | 1) class-based new and delete - overriding new nad delete on all classes
would work, but would then stop new/delete being overriden for any other
purpose. Also a single class (or hierachy) cna only use one memory
management strategy.
|
It is typically a good idea not to pollute the global namespace with
custom new/delete operators. Instead, I would provide a set of base
classes, one for each memory pool, and derive from these bases for all
classes you must allocate dynamically. For classes that use multiple
inheritance from two basis that use different allocation strategies,
you then must provide an operator new, operator new[], operator delete
and operator delete[] that redirect the request to the "right"
baseclass: You need to define the allocation strategy for this class
anyhow, so this step is just a logical consequence that cannot be avoided.
| Quote: | 2) calling the destructor explicitly. This soes actually work pretty well, I
can create a MACRO that specifies the type and I call the destructor
explicitly, then call 'operator delete' manually to free the memory. Trouble
is this s clunky at best.
|
I would call this approach "unusable". (-;
| Quote: | What I really want is a placement-delete, and I can't understand why there
isn't one!
|
Well, there is one, but it isn't called in places where you expect it,
namely by a delete-expression. It is only called in, ehem, exceptional
situations (literally). And even if there were a placement delete, it
would cost exactly the same overhead as any construction you would program
yourself.
The *real* problem is not the overhead. The real problem is the bad,
or rather absent language support to solve the alignment problem for this
construction. The rest would be "syntatic sugar". In that sense, I have
to agree that the language support for custom allocation strategies is
rather weak, yes.
So long,
Thomas
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Alf P. Steinbach Guest
|
Posted: Fri Dec 16, 2005 4:53 pm Post subject: Re: Limitation of C++ new & delete? Please prove me wrong |
|
|
* Nick C:
| Quote: | I think I have found a bit of a limitation of the C++ language. Hopefully I
will be rigorously corrected with glorious solutions to my problem. I'll try
to be as concise as possible....
The problem is I want a strategy to allow various memory-allocation
strategies to be applied. This would be useful for the following reasons:
1) I may want various allocations from various areas of my design to be
identified to allow diagnostics of memory usage.
2) I may want to apply different allocation strategies based on usage (e.g
normal heap for bitmaps, pool-based system for messages etc..)
[snip]
The only other option to identify deletes is a free-list, but this is too
slow (and also has the overhead).
|
I don't see how you can identify a per-object allocator by using a
free-list. Presumably you mean instead, that each allocator keeps track of
all currently allocated objects. I.e. an allocated-list.
Here are some ways to ensure or identify an allocation scheme:
* Global ::operator new and ::operator delete.
* Per class or group of classes, using static allocator objects that can
be changed dynamically (preferentially only at start-up...).
* Per class or group of classes by implementing a class' operator new and
operator delete.
* Per object, storing an identification of the allocation scheme in
each object.
* Per group of objects, storing an identification of the allocation
scheme externally to the objects. E.g., that all objects in a
container uses an allocation scheme identified by that container. Or
e.g. by computing the relevant allocator from an object's address.
More esoteric and fragile schemes are also possible, e.g. that between times
T1 and T2 all allocations and deallocations use scheme X, and that all
objects allocated in this time frame, and only those objects, must be
deallocated in this time frame.
| Quote: | Other solutions I have looked at are
1) class-based new and delete - overriding new nad delete on all classes
would work, but would then stop new/delete being overriden for any other
purpose. Also a single class (or hierachy) cna only use one memory
management strategy.
|
I'm not sure how the conclusions here come about. I think there is perhaps
something you haven't explained.
| Quote: | 2) calling the destructor explicitly. This soes actually work pretty well, I
can create a MACRO that specifies the type and I call the destructor
explicitly, then call 'operator delete' manually to free the memory. Trouble
is this s clunky at best.
|
(2) means that the client code knows the allocation scheme, and your only
problem is communicating that scheme to operator delete. Why not use an
old-fashioned static variable to communicate the allocation scheme? Like,
template< typename T >
void callDelete( T* p, Allocator& a = ::defaultAllocator )
{
Allocator* oldAllocator = ::theAllocator;
::theAllocator = &a;
delete p;
::theAllocator = oldAllocator;
}
The restoration of ::theAllocator necessary because the T destructor might
in turn call callDelete, so without that ::theAllocator might have been
changed when T::~T has finished and T::operator delete is called.
Of course that doesn't support threading unless you add locking or use
thread-local storage for the static variable, and since much of the point of
having different allocators or at least different heaps for objects of the
same class, is precisely to avoid locking (serialization), thread-local
storage seems then to be indicated.
But that's nearly off-topic in clc++m...
| Quote: | What I really want is a placement-delete, and I can't understand why there
isn't one! To summarise, I can't take the performance hit on using the
natural syntax '(placement) new', but also do not wnat to enforce system
wide memory allocation routines that are used in favour of new/delete.
|
See above -- but are you really sure that you need per-object schemes?
--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Ivan Vecerina Guest
|
Posted: Sat Dec 17, 2005 11:02 am Post subject: Re: Limitation of C++ new & delete? Please prove me wrong |
|
|
"Nick C" <nick (AT) google (DOT) com> wrote
:I think I have found a bit of a limitation of the C++ language. Hopefully
I
: will be rigorously corrected with glorious solutions to my problem. I'll
try
: to be as concise as possible....
:
: The problem is I want a strategy to allow various memory-allocation
: strategies to be applied. This would be useful for the following
reasons:
:
: 1) I may want various allocations from various areas of my design to be
: identified to allow diagnostics of memory usage.
:
: 2) I may want to apply different allocation strategies based on usage
(e.g
: normal heap for bitmaps, pool-based system for messages etc..)
I think that the C++ language does support such customized object alloc-
ation strategies, but under a different name: containers.
I know very well what you mean, as I had once been asking myself the
exact same question. I have settled with the following understanding:
- When the allocation strategy for an object (or specific
class/hierarchy)
is to be uniform throughout the program, then a customized new/allocator
function is the way to go.
- When individual object instances are to be allocated/managed from
instance-specific memory pools, a container is the concept that you are
actually looking for.
So in the latter case, when you are looking for an interface such
as T* p = new (pool) T(...) and delete (pool) p , one should
instead be using: container.insert(...) and container.erase(...).
Of course, there is this intermediate situation where you might want
a pool/container to store objects of any type. I think that this
defines the grey zone/dilemma that you are facing. Right now I find
this scenario to be unlikely in practice, but I remember once
looking for such a solution.
The interface I would then want to support would look like:
T* p = container.insert<T>();
T* p = container.insert(instanceOfT);
container.erase( p );
And eventually, if you are looking to be totally flexible and to let
the users call a constructor in whatever way they like, provide a
placement-new operator:
T* p new (container) T( ...ctr-params... );
: I designed a memory system that uses different allocation strategies and
: requestor-diagnosics etc. The only remaining issue was how to roll out
the
: system to the code. I am, in generael, in favour of using the built-in
: facilities of a languge and wanted to use/overried 'new' and 'delete' to
: access this new system.
:
: The answer you would think is 'placement new'. Yep! I thought so too. By
: creating a placement new, I can pass a parameter to 'operator new'. This
: parameter was an id that would tell my design which allocation stategy
to
: use and to allow diagnostics to be logged. All great so far! The trouble
was
: with 'delete'. If are still reading, then you'll probably know that
there is
: no equivalent 'placement delete' that can take and extra parameter.
Note that there is such a thing as a placement-delete operator.
They are needed by the C++ runtime when an object has been successfully
(custom-)allocated, but the construction of the instance failed (i.e.
a constructor has thrown an exception).
Most placement-new operator implementations should therefore have a
corresponding placement-delete operator defined.
But of course, this is not what you are looking for.
[...]
: Other solutions I have looked at are
: 1) class-based new and delete - overriding new nad delete on all classes
: would work, but would then stop new/delete being overriden for any other
: purpose. Also a single class (or hierachy) cna only use one memory
: management strategy.
:
: 2) calling the destructor explicitly. This soes actually work pretty
well, I
: can create a MACRO that specifies the type and I call the destructor
: explicitly, then call 'operator delete' manually to free the memory.
Trouble
: is this s clunky at best.
Again, look at it from a container's perspetive: it is natural for
a container to explicitly call a destructor when an element is
being erased.
: What I really want is a placement-delete, and I can't understand why
there
: isn't one! To summarise, I can't take the performance hit on using the
: natural syntax '(placement) new', but also do not wnat to enforce system
: wide memory allocation routines that are used in favour of new/delete.
:
: Comments very gratefully received.
As stated above, the real answer IMO is to use a container-style
interface.
Think of a memory pool as a container for objects.
I hope this perspective and the above explanations help.
Regards,
Ivan
--
http://ivan.vecerina.com/contact/?subject=NG_POST <- email contact form
Brainbench MVP for C++ <> http://www.brainbench.com
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Alberto Ganesh Barbati Guest
|
Posted: Mon Dec 19, 2005 10:18 am Post subject: Re: Limitation of C++ new & delete? Please prove me wrong |
|
|
Nick C wrote:
| Quote: | What I really want is a placement-delete, and I can't understand why there
isn't one!
|
Allowing placement delete-expressions would promote a very error-prone
programming style.
As pointed out by Alf P. Steinbach, if you want to allow for multiple
alloc/dealloc strategies for the same object type, the problem is in
being consistent between the allocation and the deallocation phase. For
example:
MyType* foo()
{
return new(FooAllocStrategy) MyType;
}
MyType* bar()
{
return new(BarAllocStrategy) MyType;
}
// possibly in a completely different file or module
void baz(MyType* ptr)
{
delete(/* which Strategy to put here? */) ptr;
}
You must therefore store some information about the allocation strategy
somewhere, that can it be used at the deallocation site. You basically
have only two alternatives: put it in the allocated object or in some
container object.
1) In the allocated object: you already considered this option, you just
add the strategy information directly inside the allocated block in the
overloaded placement-new and retrieve such info in the non-overloaded
operator delete. Another possibility is to encode the alloc strategy in
the type itself:
template <class T, class Alloc>
class AllocWrap : public T
{
public:
// Prerequisite: T MUST have a virtual destructor for this to work
// Add ctor forwarders here
void* operator new(size_t n) { return Alloc::Alloc(n); }
void operator delete(void* p) { return Alloc::Free(p); }
};
then, instead of using:
MyType* ptr = new(FooAllocStrategy) MyType;
you use:
MyType* ptr = new AllocWrap<MyType, FooAllocator>;
As long as MyType has a virtual destructor, the correct delete function
will be automatically selected. You will need to add ctor forwarders to
AllocWrap if MyType does not have a default constructor.
2) In the container: you can use standard STL containers with custom
allocator (as pointed out by Ivan Vecerina). This is by far the best
alternative, IMHO. Another option is to use the Boost pointer containers
([url]http://boost.org/libs/ptr_container)[/url]. However, if you allocate objects
one-by-one, using a container might look overkill so using a smart
pointer like boost::shared_ptr with a custom deleter might be a better
solution. The example above would become:
boost::shared_ptr<MyType> foo()
{
return boost::shared_ptr<MyType>(
new(FooAllocStrategy) MyType, FooDeallocator)
}
boost::shared_ptr<MyType> bar()
{
return boost::shared_ptr<MyType>(
new(BarAllocStrategy) MyType, BarDeallocator)
}
void baz(boost::shared_ptr<MyType>& ptr)
{
ptr.reset(); // will use the correct deallocator
}
Of course this approach requires some overhead that you may not afford
to pay in your specific use case. OTOH, it may make your code much more
robust than using plain pointers ;-)
HTH,
Ganesh
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Wu Yongwei Guest
|
Posted: Mon Dec 19, 2005 10:40 am Post subject: Re: Limitation of C++ new & delete? Please prove me wrong |
|
|
If you can decide the memory allocation strategy at compile time
(instead of run time), then template techniques can help. See the
following code for an example:
http://cvs.sourceforge.net/viewcvs.py/nvwa/nvwa/static_mem_pool.h?view=markup
If need be, you may also consult my article on its design:
http://wyw.dcweb.cn/static_mem_pool.htm
Best regards,
Yongwei
Nick C wrote:
| Quote: | I think I have found a bit of a limitation of the C++ language. Hopefully I
will be rigorously corrected with glorious solutions to my problem. I'll try
to be as concise as possible....
The problem is I want a strategy to allow various memory-allocation
strategies to be applied. This would be useful for the following reasons:
1) I may want various allocations from various areas of my design to be
identified to allow diagnostics of memory usage.
2) I may want to apply different allocation strategies based on usage (e.g
normal heap for bitmaps, pool-based system for messages etc..)
|
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Mirek Fidler Guest
|
Posted: Mon Dec 19, 2005 1:17 pm Post subject: Re: Limitation of C++ new & delete? Please prove me wrong |
|
|
| Quote: | 2) calling the destructor explicitly. This soes actually work pretty well, I
can create a MACRO that specifies the type and I call the destructor
explicitly, then call 'operator delete' manually to free the memory. Trouble
is this s clunky at best.
|
What about template instead of macro?
template <class T>
void my_delete(T *ptr)
{
ptr->T::~T();
my_deallocation_routine(ptr);
}
Does not look too clunky to me...
Other than that, I guess that the right solution here is in fact global
new/delete replacement....
Mirek
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Michiel.Salters@tomtom.co Guest
|
Posted: Mon Dec 19, 2005 1:50 pm Post subject: Re: Limitation of C++ new & delete? Please prove me wrong |
|
|
Nick C wrote:
| Quote: | ... I want a strategy to allow various memory-allocation
strategies to be applied. This would be useful for the following reasons:
1) I may want various allocations from various areas of my design to be
identified to allow diagnostics of memory usage.
2) I may want to apply different allocation strategies based on usage (e.g
normal heap for bitmaps, pool-based system for messages etc..)
... The trouble was with 'delete'. ... there is
no equivalent 'placement delete' that can take and extra parameter.
Therefore my system has no way to know which de-allocation strategy to apply
(and makes the diagnostics meaningless). The only options are to do things
like, heap mangagement - i.e when allocaing, and an extra bit of info to
enable the de-allocate to work out what to do. Trouble is this means invalid
'delete' cause exceptions! Also, and extra 4-bytes per allocation is a big
overhead for small allocations.
The only other option to identify deletes is a free-list, but this is too
slow (and also has the overhead).
|
I don't believe that. And that's because I have written an allocator
that did
this for 100 million concurrent allocations, not because I think it
should.
Of course, you don't actually store information for each pointer, but
you
store the information per block. I.e. if you have an 4 byte allocation
with
type X, you allocate those from private 64Kb heaps H<X>. The overhead
is a few bytes per 4000 allocations. When you have to lookup a pointer
during deletion, you can do so in O(log(N)) where N is the number of
heaps. Even with a thousand heaps, log(N)=10 and the memory overhead
is a few KB on a total of several MB.
HTH,
Michiel Salters
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Eric B Guest
|
Posted: Mon Dec 19, 2005 3:56 pm Post subject: Re: Limitation of C++ new & delete? Please prove me wrong |
|
|
[email]Michiel.Salters (AT) tomtom (DOT) com[/email] wrote:
| Quote: | Nick C wrote:
... I want a strategy to allow various memory-allocation
strategies to be applied. This would be useful for the following reasons:
1) I may want various allocations from various areas of my design to be
identified to allow diagnostics of memory usage.
2) I may want to apply different allocation strategies based on usage (e.g
normal heap for bitmaps, pool-based system for messages etc..)
... The trouble was with 'delete'. ... there is
no equivalent 'placement delete' that can take and extra parameter.
Therefore my system has no way to know which de-allocation strategy to apply
(and makes the diagnostics meaningless). The only options are to do things
like, heap mangagement - i.e when allocaing, and an extra bit of info to
enable the de-allocate to work out what to do. Trouble is this means invalid
'delete' cause exceptions! Also, and extra 4-bytes per allocation is a big
overhead for small allocations.
The only other option to identify deletes is a free-list, but this is too
slow (and also has the overhead).
I don't believe that. And that's because I have written an allocator
that did
this for 100 million concurrent allocations, not because I think it
should.
Of course, you don't actually store information for each pointer, but
you
store the information per block. I.e. if you have an 4 byte allocation
with
type X, you allocate those from private 64Kb heaps H<X>. The overhead
is a few bytes per 4000 allocations. When you have to lookup a pointer
during deletion, you can do so in O(log(N)) where N is the number of
heaps. Even with a thousand heaps, log(N)=10 and the memory overhead
is a few KB on a total of several MB.
|
I understand Nick's dilemma. For us, the bottleneck wasn't space or
even the time spent in the allocator code. It was the fact that if you
have one allocator, it must LOCK, and the contention with multiple
threads was causing unacceptable delays. So we needed to create a
separate non-protected allocator object (not just pool) for certain
components. However, I could find no clean way to do this in the
general purpose case (i.e. operator new specifying which allocator
object to use). We are now researching nonblocking memory allocators as
a solution.
Eric Beyeler
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|