Page 1 of 1
Knowing new[]'s overhead in a compiler-independent way
Posted: Tue Jul 05, 2011 10:06 am
by Neolander
In C++, the array version of new allocates some extra storage space alongside the allocated object, so that it may store the array's size in order to call each element's destructor later.
My question is : is there a clean, compiler-agnostic way to know about the size of the actually allocated object (overhead included) without actually performing the allocation ?
The only option which I currently see is to create a special version of operator new[] for that purpose, which takes a size_t reference as a parameter, stores the result in it, and always returns NULL. Not exactly what I'd call clean, as it creates some very confusing syntax. ("Wait a minute, why does he use placement new here to do... err... what ?")
Any better idea ?
Re: Knowing new[]'s overhead in a compiler-independent way
Posted: Tue Jul 05, 2011 10:22 am
by bluemoon
But why would you try to optimize new, and introduce a special new that may break with other code?
And I seriously doubt that extra tidy size, along with other possible header and footer, make a sensible different in terms of memory footprint for array of elements,
and the related processing time is neglectable compare with the actual memory allocation.
My question is : is there a clean, compiler-agnostic way to know about the size of the actually allocated object (overhead included) without actually performing the allocation ?
memory allocation routines (new) are defined in the stdc++ library, and can be replaced.
it is meant to be isolated from compiler, so your question on "compiler-agnostic" way, well, the whole business is compiler-agnostic.
To determinate the size, check the library source code.
Re: Knowing new[]'s overhead in a compiler-independent way
Posted: Tue Jul 05, 2011 10:34 am
by Owen
...the size-of-array header is added by the compiler, not the library.
Also, be aware: if your operator new returns NULL, std::bad_alloc will be thrown.
Re: Knowing new[]'s overhead in a compiler-independent way
Posted: Tue Jul 05, 2011 10:49 am
by Neolander
@Owen : Nope, because I have followed berkus' advice of putting a throw() somewhere in my allocator declarations
User-space new and delete will probably be standards-compliant and have full exception support, but at kernel level I want neither exceptions nor the hurdle of playing with nothrow objects all the time, so standards be damned...
@bluemoon : As Owen says, the situation is not this simple. When you write...
Code: Select all
Foo* bar = new Foo[5]();
delete[] bar;
...four things happen :
- Memory for the array is allocated
- Each Foo in the array is initialized
- Each Foo in the array is destroyed
- Memory for the array is freed
The funny part is, library implementations only take care of 1 and 4. 2 and 3 are the job of the compiler. A corollary of this is that libraries may only implement the memory allocator part of new[] (operator new[]), which is basically a shortcut for malloc : you get asked to allocate x bytes of data, without knowing which part will be used to store the compiler's management structures, and which part actually contains the array.
So before operator new[] is called, there is no obvious way to know how much memory will actually have to be allocated by it. And for what I want to do (avoiding multiple allocations by allocating one big buffer and slicing it in bits), this is a problem. Hence my question : is there a clean way to know, without performing any allocation, how much memory a new[] will eat up ? A way that does not involve dirty hacks like an overloaded new[] that looks like a placement new and doesn't actually allocate memory...
Re: Knowing new[]'s overhead in a compiler-independent way
Posted: Wed Jul 06, 2011 2:26 am
by Solar
...and the compiler will slice it in whatever way applicable.
I think you're on a wild goose chase here.
Re: Knowing new[]'s overhead in a compiler-independent way
Posted: Wed Jul 06, 2011 3:54 am
by JamesM
Code: Select all
static bool initializing = false;
static size_t overhead = 0;
void *operator new[](size_t sz) {
if (initializing) {
overhead = sz;
return (void*)~0UL;
} else {
// Do normal memory allocation
}
}
void init() {
initializing = true;
volatile void *x = new int[0];
initializing = false;
}
?
Re: Knowing new[]'s overhead in a compiler-independent way
Posted: Wed Jul 06, 2011 4:30 am
by Neolander
JamesM wrote:Code: Select all
static bool initializing = false;
static size_t overhead = 0;
void *operator new[](size_t sz) {
if (initializing) {
overhead = sz;
return (void*)~0UL;
} else {
// Do normal memory allocation
}
}
void init() {
initializing = true;
volatile void *x = new int[0];
initializing = false;
}
?
I think this is the option I'd end up choosing, save for some tweaking. Still a bit ugly, but better than my idea.
Re: Knowing new[]'s overhead in a compiler-independent way
Posted: Wed Jul 06, 2011 4:37 am
by Neolander
berkus wrote:I honestly don't follow what's the problem. Your operator new[] implementation will be called with exactly how many bytes are needed, including the overhead.
I want to know how much memory is needed by a new[] before actually allocating the memory
The idea is that in a scenario where I'd have to allocate lots of related small heap objects that will also be freed at the same time (strings, typically), I can (and need to) get much better performance by calculating the amount of required memory and allocating everything at once.
Re: Knowing new[]'s overhead in a compiler-independent way
Posted: Mon Jul 25, 2011 7:02 am
by Ready4Dis
Last time I played around overloading new for some memory management/tracking software, if I did a new char[10], it would ask my new for exactly 10 bytes. (When I say overloaded, I don't mean a single overload for a class, just overloaded generic new/delete). As far as I know, new doesn't have much overhead over than what is used by whatever malloc implementation it calls, which is obviously dependant on your particular malloc. I could be wrong (wouldn't be the first time), but unless you use something with GC (garbage collection) new shouldn't need any extra space. If you're writing an OS, you are probably going to have to use your own NEW implementation anyways, so it's up to you what overhead it has. If you are using a cross compiled GCC, look at the sources to see if it doesn't anything special for new. I'm not really sure what overhead you are talking about or looking to avoid (overhead as in cpu cycles, or in memory footprint).
Re: Knowing new[]'s overhead in a compiler-independent way
Posted: Mon Jul 25, 2011 11:31 am
by Owen
..try "new SomeTypeWithADestructor[10]"
Re: Knowing new[]'s overhead in a compiler-independent way
Posted: Thu Jul 28, 2011 11:02 am
by blobmiester
Owen wrote:..try "new SomeTypeWithADestructor[10]"
Which will translate into (theoretically equivalent) (SomeTypeWithADestructor*)malloc(sizeof (SomeTypeWithADestructor) * 10).
The destructor/constructor calling is handled by the compiler at new/delete for the type.
As for new[]'s overhead. The compiler doesn't decide what it is. The implementation of operator new() does. There is no possible way to detect this or control it -- unless you write your own malloc/new implementation (which isn't that hard if you are caring this much about allocation speed).
On second thought, you could just malloc() a pool of memory and use placement new/delete to allocate (which is what the STL does). That is what I'd do.
Re: Knowing new[]'s overhead in a compiler-independent way
Posted: Thu Jul 28, 2011 4:04 pm
by Owen
blobmiester wrote:Owen wrote:..try "new SomeTypeWithADestructor[10]"
Which will translate into (theoretically equivalent) (SomeTypeWithADestructor*)malloc(sizeof (SomeTypeWithADestructor) * 10).
If it translates into that, how does delete [] thatBuffer know how many destructors it needs to run? Conclusion: It doesn't translate into that.
It translates into ::operator new[](some value > sizeof (T) * 10).
To start writing things in pseudo-C++0X, the compiler-side logic for new probably looks something like the following:
Code: Select all
T* buf;
if(alignof(T) > alignof(size_t)) {
buf = ::operator new(sizeof(T) * (nElements + 1));
size_t* count = (size_t*) &buf[0];
*count = nElements;
buf += 1;
} else {
size_t* count = ::operator new(sizeof(T) * nElements + sizeof(size_t));
buf = (T*) count[1];
*count = nElements;
}
for(size_t i = 0; i < nElements; i++) buf[i]->T();
return buf
The destructor/constructor calling is handled by the compiler at new/delete for the type.
Re: Knowing new[]'s overhead in a compiler-independent way
Posted: Fri Jul 29, 2011 7:12 am
by Neolander
And this is exactly what I got in practice ! Good to know that new[] avoids wasting space on types without a destructor though
(Ah, a deep breath of 'net after some internet-less holidays)