Price of Creating Local Objects

C

cppaddict

I have a method that uses a fairly large object. The choice is
between having a local object in the method or a static member object
that the method uses.

------CHOICE 1---------

int MyClass::myMethod(int param) {
MyBigObject o();
//initialize o based on param
//do calculations with o
return calclulatedValue;
}

------CHOICE 2---------

int MyClass::myMethod(int param) {
const MyBigObject& o = m_staticMemberHoldingAMyBigObject;
//re-initialzie o based on param
// rest is same as above
}

How much extra work is involved in the creation of the local object
with each call of myMethod()? More precisely, what actually happens?
Is new memory allocated for the object each time? Is the memory
allocated on the stack? On a temporary stack which exists during the
method call? I'm trying to understand what goes on under the hood as
well as find an answer to the practical problem.

Is it also true that choice 1 would be thread safe, while choice 2
would not?

Thanks for any help,
cpp
 
D

David Hilsee

cppaddict said:
I have a method that uses a fairly large object. The choice is
between having a local object in the method or a static member object
that the method uses.

How large is large? 50 bytes? 1 kilobyte? 1 megabyte?
------CHOICE 1---------

int MyClass::myMethod(int param) {
MyBigObject o();

Declares a method named "o" that takes no arguments and returns a
MyBigObject. You probably meant

MyBigObject o;
//initialize o based on param
//do calculations with o
return calclulatedValue;
}

------CHOICE 2---------

int MyClass::myMethod(int param) {
const MyBigObject& o = m_staticMemberHoldingAMyBigObject;
//re-initialzie o based on param
// rest is same as above
}

How much extra work is involved in the creation of the local object
with each call of myMethod()? More precisely, what actually happens?
Is new memory allocated for the object each time? Is the memory
allocated on the stack? On a temporary stack which exists during the
method call? I'm trying to understand what goes on under the hood as
well as find an answer to the practical problem.

In general, variables that are declared locally within a function are
allocated quickly. If the object were monstrous, then I could see how one
might want to avoid declaring it as a local variable to a function, but that
generally deals with issues of <implementation>stack space</implementation>.
I wouldn't worry too much about what actually happens. Instead, concentrate
on questions like "How fast is it?" It's easy to take measurements and
determine answers for questions about efficiency. If you're concerned that
the program might fail because the object is not a static member of a class,
then, by all means, consult the implementation.
Is it also true that choice 1 would be thread safe, while choice 2
would not?

Threads are not a part of standard C++, but, for every implementation that I
could imagine, the first is thread-safe and the second is not, unless you
provide a mutex.
 
C

cppaddict

How large is large? 50 bytes? 1 kilobyte? 1 megabyte?

About 1 kilobyte.
Declares a method named "o" that takes no arguments and returns a
MyBigObject. You probably meant

MyBigObject o;

Woops. Yes, that is what I meant.
In general, variables that are declared locally within a function are
allocated quickly. If the object were monstrous, then I could see how one
might want to avoid declaring it as a local variable to a function, but that
generally deals with issues of <implementation>stack space</implementation>.
I wouldn't worry too much about what actually happens. Instead, concentrate
on questions like "How fast is it?"

I was hoping to get a feel for "How fast is it?" by understanding what
goes on behind the scenes. Of course, I could just time it and see,
but then I would have no insight. I'm actually pretty sure that speed
would not be an issue, but only because I vaguely know that vaguely
similar code has executed quickly.
If you're concerned that
the program might fail because the object is not a static member of a class,
then, by all means, consult the implementation.

That is not a concern. Is there any reason you think it should be?
Threads are not a part of standard C++, but, for every implementation that I
could imagine, the first is thread-safe and the second is not, unless you
provide a mutex.

Thank for your help,
cpp
 
D

David Hilsee

cppaddict said:
About 1 kilobyte.

That's probably nothing to be concerned about. I've dealt with C programs
that, in nearly every function, allocated around 500 bytes just for a
temporary sprintf() buffer.
I was hoping to get a feel for "How fast is it?" by understanding what
goes on behind the scenes. Of course, I could just time it and see,
but then I would have no insight. I'm actually pretty sure that speed
would not be an issue, but only because I vaguely know that vaguely
similar code has executed quickly.

If you really want to know exactly what is going on behind the scenes, you
should examine the implementation. If you're more interested in how fast it
executes, then measurements will be more helpful. In general, it is
relatively quick, because local variables usually result in some fiddling
with the stack, which is usually a cheap operation. Of course, any comments
mentioning to a "stack" are referring to a possibly common implementation.
That is not a concern. Is there any reason you think it should be?

Well, as I mentioned before, there can be a "stack space" exhaustion issue,
but that's not usually a problem for most applications. It's more of a
problem for applications that use highly recursive algorithms.
 
D

Dave Townsend

cppaddict said:
I have a method that uses a fairly large object. The choice is
between having a local object in the method or a static member object
that the method uses.

------CHOICE 1---------

int MyClass::myMethod(int param) {
MyBigObject o();
//initialize o based on param
//do calculations with o
return calclulatedValue;
}

------CHOICE 2---------

int MyClass::myMethod(int param) {
const MyBigObject& o = m_staticMemberHoldingAMyBigObject;
//re-initialzie o based on param
// rest is same as above
}

How much extra work is involved in the creation of the local object
with each call of myMethod()? More precisely, what actually happens?
Is new memory allocated for the object each time? Is the memory
allocated on the stack? On a temporary stack which exists during the
method call? I'm trying to understand what goes on under the hood as
well as find an answer to the practical problem.

Is it also true that choice 1 would be thread safe, while choice 2
would not?

Thanks for any help,
cpp

From what you have described, its impossible to advise you
on what effort is involved. When you declare an object in
a member function as in case 1, memory for the object is
provided by the stack, although internally the object may also
allocate memory using the free-store (new). Generally, allocating
with the free store is more expensive in run-time than the stack approach,
and memory obtained from the free-store should also be "freed" which is
another operation which
is not required when you allocate objects on the stack. Object allocation
and
deallocation on the stack is very fast since its just a matter of keeping
track
of the high and low addresses which bound an object. What's more, as
objects
as destroyed automatically as they go out of scope, the memory the objects
use is
recycled. However, the stack is of course of finite size, so if you are
going to have deeply nested calls which allocate large objects on the stack
, you mightwant to reconsider how you allocate your objects.

Of the architectures I know, there is not a "temporary" stack, there's the
one stack, it just grows to handle the data used in a function call and
shrinks back when the call returns, its just one contiguous area of memory.

There is not enough information to tell if choice 1 or choice 2 is thread
safe.
You only have to worry about thread safety when you are sharing a single
resource
between multiple threads and the threads can potentially change the state of
that resource.
If the object in choice1 is actually accessing such a shared resource, then
its not thread safe,
even though only one thread can access the object.
Choice 2 is actually a reasonable approach in a multi-threaded enviroment
when you add synchonrization objects (locks) to serialize access to the
static object.

dave
 
C

cppaddict

Generally, allocating
with the free store is more expensive in run-time than the stack approach,
and memory obtained from the free-store should also be "freed" which is
another operation which
is not required when you allocate objects on the stack. Object allocation
and
deallocation on the stack is very fast since its just a matter of keeping
track
of the high and low addresses which bound an object.

Dave,

Thanks for your thoughts. I did know that using the heap is more
expensive than the using the stack, but could you explain why that is?

What are all the extra things that need to be done?

Also, when you say that allocating on the stack is just a matter of
tracking the high and low addresses, that does not include the expense
of object initialization, does it? That is, it doesn't include the
time it takes to execute the code in the objects constructor? Or does
it?

Thanks again,
cpp
 
A

Ali Cehreli

Dave,

Thanks for your thoughts. I did know that using the heap is more
expensive than the using the stack, but could you explain why that is?

All this is implementation specific of course but I think very common.
Every sizable object needs some memory to live on. The memory for
automatic objects is allocated as cheaply as adjusting a register (stack
pointer).

Modifying the stack pointer reduces/increases available stack
space. Objects live on the stack one after the other.
What are all the extra things that need to be done?

When memory is explicitly requested for an object by operator new, then
the memory allocator must find a suitable place for an object of that
particular size.

Pool allocators keep available chunks of memory according to their
sizes. For example, objects having sizes 32 to 64 bytes could live in
the same memory block. This could be to ensure that small objects are
kept together so that large memory chunks are available for larger
objects.

When the object is deleted later on, the memory is returned to the
appropriate pool.

All of this takes CPU time
Also, when you say that allocating on the stack is just a matter of
tracking the high and low addresses, that does not include the expense
of object initialization, does it? That is, it doesn't include the
time it takes to execute the code in the objects constructor?

We are not talking about object construction on that memory, because the
cost of construction is the same for automatic vs. dynamic objects.

Ali
 
L

lilburne

cppaddict said:
Also, when you say that allocating on the stack is just a matter of
tracking the high and low addresses, that does not include the expense
of object initialization, does it? That is, it doesn't include the
time it takes to execute the code in the objects constructor? Or does
it?

First the space has to be found in free store. This might be require
requesting space from the OS it could also involve a search of the free
blocks (though most allocators keep a sorted list of block on size).

Deletion will involve return the block to free store, coallesced it with
surounding free blocks etc, updating the sorted list of free blocks.

You'll really need to check on the implementation you are using. But
I'll tell you that on a windows system new/delete is very expensive.
 
J

Jerry Coffin

cppaddict said:
I have a method that uses a fairly large object. The choice is
between having a local object in the method or a static member object
that the method uses.

The factor to consider is not really the size of the object, but the
amount of work required to initialize the object. A large object
that's left mostly uninitialized until use might be much cheaper to
create than a tiny object that's initialized by retrieving data from
(say) a database over the network.

[ ... ]
How much extra work is involved in the creation of the local object
with each call of myMethod()?

That depends on what the object's ctor does.
More precisely, what actually happens?
Is new memory allocated for the object each time? Is the memory
allocated on the stack?

With a typical machine, space for local objects is allocated on a
stack. Allocating stack space is roughly constant time regardless of
size (barring things like paging getting involved).
Is it also true that choice 1 would be thread safe, while choice 2
would not?

Generally speaking, yes.
 
D

Dave Townsend

cppaddict said:
Dave,

Thanks for your thoughts. I did know that using the heap is more
expensive than the using the stack, but could you explain why that is?

What are all the extra things that need to be done?

Also, when you say that allocating on the stack is just a matter of
tracking the high and low addresses, that does not include the expense
of object initialization, does it? That is, it doesn't include the
time it takes to execute the code in the objects constructor? Or does
it?

Thanks again,
cpp

Each implementation of the freestore/heap has its own optimizations and
(proprietary) implementation details, but the general approach is as
follows:

The free store manages memory for allocations by first obtaining
memory from the operating system in large contiguous chunks. Individual
requests for memory are made out of these chunks. Internally the free-store
manager maintains knowledge of what memory has been allocated and what
is available for requests. When you make a request for a memory allocation
through new (or malloc) the manager will check to see if it has a suitable
piece
of memory on hand, and if so, will provide you with an allocation. If not,
then
it will make calls to the operation system ("sbreak") to obtain more memory
if possible and
then try to make your allocation. Usually, the piece of memory you obtain
from
the heap is slightly bigger than you requested, typically, the free bytes
before the
actual pointer value you get are dedicated to the manager's book keeping so
that
the memory can be re-absorbed into the free-store when you deallocate/delete
it.
( there are also issues of alignment, memory is usually allocated on 8 byte
(typically)
boundaries so that any datatype (ie double) can be correctly aligned, also
allocations
are usually rounded up to 4 or 8 byte multiples for convenience).

When you deallocate (delete) a piece of memory, the memory is "reabsorbed"
into the
system. Some systems will try to coallesc pieces of deallocated memory
together to form the largest
contigious range as part of a strategy to avoid "fragmentation" of the
system's memory.

Some systems provide a useful debugging feature where memory is "painted" in
certain patterns
to indicate the memory has been allocated but not initialized, or
deallocated.


A number of implementation efficiencies can be incoporated into any
particular system which greatly improves the run-time efficiency and memory
efficiency. Still, there are usually a number of function
calls made to allocate and deallocate a block, even under the best
circumstances when memory
is on-hand for the manager to dole out to the caller. I don't have actual
numbers to hang my
hat on, but the stack allocation is certainly a lot faster than the
freestore/heap allocation. .
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,175
Messages
2,570,942
Members
47,489
Latest member
BrigidaD91

Latest Threads

Top