operator new - good, bad, or ugly?

I have a hard real-time application written in C++. In order to avoid
memory fragmentation and associated memory allocation latencies, the
application avoids “new”-ing and “delete”-ing objects after initial startup.
Is this necessary? Do any compilers / OSes mitigate the necessity?

MU

“Mark Uebel” <mark.uebel@mmt.bellhowell.com> wrote in message
news:9hbc6r$t2v$1@inn.qnx.com

I have a hard real-time application written in C++. In order to avoid
memory fragmentation and associated memory allocation latencies, the
application avoids “new”-ing and “delete”-ing objects after initial
startup.
Is this necessary? Do any compilers / OSes mitigate the necessity?

new and delete is the same a malloc/free. With QNX4 I’ve seen cases where
memory fragmentation caused the heap to grow. Memory fragmentation is
a concern within the heap only and not necessarely with the OS memory as
memory is virtual.

Although not necessary I consider avoiding malloc/free at run time a good
thing.
malloc is usually fast but execution time can vary depening if heap needs to
be grown or not.


MU

In article <9hbc6r$t2v$1@inn.qnx.com>,
Mark Uebel <mark.uebel@mmt.bellhowell.com> wrote:

I have a hard real-time application written in C++. In order to avoid
memory fragmentation and associated memory allocation latencies, the
application avoids “new”-ing and “delete”-ing objects after initial startup.
Is this necessary? Do any compilers / OSes mitigate the necessity?

MU

Well, as is pointed out in the other follow-up, using new and delete
is no different from malloc/free – almost. There is the relatively
minor issue of constructors – which won’t affect you if your classes
are rationally designed for predictable timing behavior.

Therefore, in normal circumstances, you have the same issues as malloc/free.
If it is a periodic system – presumably, yes, since you describe it
as hard realtime – then malloc couldn’t provide a fixed upper bound
on execution time, so it could only be modeled stochastically. Otherwise,
it would normally be simpler to do only zoned allocation from within
the realtime thread, and preallocate a fixed size pool of buffers for the
zone used by the realtime thread.

In the latter case, your code can be kept clean with the
use of custom new and delete operators. These operators can perform the
allocation by taking blocks from the free list for the zone, or simply
put them back on the free list. It gets a bit tricky, though,
if you want to use new and delete operators for a class. You have to
be sure to override new and delete on sub-classes if they differ in
size – i.e. they have any new members.

With a little book-keeping, you can create a placement new operator
that allows you to do allocations from a particular zone. When you
do this, however, you must also override the global operator delete
to ensure that the buffer is freed back to the correct zone.

The following is over-simplified, but it gives the gist of the idea.
Note that the more different types of basic allocation policies you
try to deal with, the more complicated the global new and delete
operators may become. In fact, if you adopt this approach it is
better to use the basic allocator templates from the STL as the
basis of your zone allocators.

e.g.
class AllocatorZone {…};
enum AllocatorType { zoned, heap };
struct BufferHeader {…};

void *
operator new (std::size_t size, AllocatorZone *zone)
throws (std::bad_alloc)
{
// Correct behavior must check if ptr is NULL, and
// call the new_handler if it is
BufferHeader *bh = zone->alloc();
zone->head = zone->head->next;
// Must actually check the size
if (bh->size < size) throw std::bad_alloc();
bh->zone = zone; // Assuming it isn’t stuck there
bh->type = AllocatorType::zoned; // Assuming it isn’t stuck there
return (void *)bh;
}

void operator delete(void *ptr) throws()
{
BufferHeader *bh = (BufferHeader *)ptr;
if (bh->type == AllocatorType::zoned) {
bh->zone->release();
} else {

}
}

Steve Furr email: furr@qnx.com
QNX Software Systems, Ltd.