Allocating memory on the stack or heap
I was asked some months ago if I knew how to allocate memory on the stack versus the heap (C or C++ related). I wasn't able to answer the question, and since then I've been looking for a good answer. I've done a bit of research on the subject and I wanted to see if someone could verify for me if I'm going in the right direction. And there's some follow-on questions that I have now, as well.
Thus far what I've found out (and please correct me if I'm wrong (and why was this so hard to find?? Am I just stupid?)) is that by not using a memory allocation function memory is automatically allocated on the stack. Thus:
int a = 5; <- memory from the stack
But if I do this:
int* a = new int; <- c++
or
int* a = (int)malloc(sizeof(int)); <- c
I get memory from the heap.
Assuming that's correct, aren't there limits to using stack memory? And if there are, how do I find out what the sizes are (I'm assuming that this is operating system dependent)? Let's say I have some big huge array that I suddenly decide absolutely has to be on the stack, is there some way of dynamically resizing a stack to make room for it? For that matter, are there pros/cons (other than memory size limitations) I would want memory from one or the other?
Thanks for your help with this,
- Goishin
Quote:Original post by GoishinIt depends on your OS, yes. And your compiler. One of the linker settings is "Stack reserve size", which last time I checked was 1MB for Visual Studio (Can't remember what version, probably 2003).
But if I do this:
int* a = new int; <- c++
or
int* a = (int)malloc(sizeof(int)); <- c
I get memory from the heap.
Assuming that's correct, aren't there limits to using stack memory? And if there are, how do I find out what the sizes are (I'm assuming that this is operating system dependent)? Let's say I have some big huge array that I suddenly decide absolutely has to be on the stack, is there some way of dynamically resizing a stack to make room for it? For that matter, are there pros/cons (other than memory size limitations) I would want memory from one or the other?
The stack is allocated as a fixed size chunk of memory when your application starts, and each thread in your app gets it's own stack (You're probably just using the one thread, which is the main thread created by the OS).
The stack isn't just used for your variables though, there's also information in there about where a return statement returns to, and suchlike.
Every time you call a function, the code will start a new function at the next free space on the stack, and put that functions local variables (stack variables) there. So, if you have two functions called funcA() and funcB(), and funcA() has 100 bytes used in local variables, then calls funcB(), which allocates 200 bytes, you'll use a little over 300 bytes of stack (100 for funcA, 200 for funcB, and a little added by the compiler to tell it where to return to when funcB finishes).
When you allocate memory from the heap, you're technically allocating memory on the heap and stack. When you do:
int* a = new int[10];
You're allocating 10*sizeof(int) bytes from the heap (Usually sizeof(int) == 4, so that'd be 40 bytes). You also store sizeof(int*) bytes on the stack, which is the actual value of a (Again, usually 4 on a 32-bit OS), and that value is a pointer to tell the CPU where the 40 byte chunk exists.
Hope that helps a bit...
Quote:For that matter, are there pros/cons (other than memory size limitations) I would want memory from one or the other?
One thing you have to consider is that any memory allocated on the stack by the current function will be returned when the function returns. Thus any memory that you want left intact after the function returns will have to be allocated on the heap.
Any memory areas with it's size unknown at compile time will also have to be allocated on the heap.
Allocating very large amounts of memory from the stack is not recommended since a dynamic allocation from the heap can fail wheres you'll run into problems if the stack is filled...
Quote:Original post by GoishinDynamic memory allocation is generally slow. Allocating memory on the stack is essentially free. It's going through a linked list of allocations, finding a block that's a reasonable size, and possibly allocating memory from the OS versus just changing a register from one value to another.
For that matter, are there pros/cons (other than memory size limitations) I would want memory from one or the other?
Thanks guys(by the way, diggin' on your username there Steve).
That's helping. But also generating new questions [smile]
If memory on the stack is returned when a function returns, how are static variables (in a function, not global) handled? Is that memory stored on the heap instead?
And if stack memory is around a meg, aren't you in danger of of running out of stack space when using recursion(assuming whatever you're recursing is going to be doing a WHOLE bunch of recursing)?
- Goishin
That's helping. But also generating new questions [smile]
If memory on the stack is returned when a function returns, how are static variables (in a function, not global) handled? Is that memory stored on the heap instead?
And if stack memory is around a meg, aren't you in danger of of running out of stack space when using recursion(assuming whatever you're recursing is going to be doing a WHOLE bunch of recursing)?
- Goishin
Quote:Original post by Evil SteveQuote:Original post by GoishinDynamic memory allocation is generally slow. Allocating memory on the stack is essentially free. It's going through a linked list of allocations, finding a block that's a reasonable size, and possibly allocating memory from the OS versus just changing a register from one value to another.
For that matter, are there pros/cons (other than memory size limitations) I would want memory from one or the other?
Is this how it actually works though? I had a game that suddenly became very very slow to start up. I found this was because a function called many times at start up had a largish array in it. I guessed the speed was due to the memory was being re-allocated.
I moved the array to the global scope. Result game started at normal (near instant) speed. So what happened there?
Quote:
If memory on the stack is returned when a function returns, how are static variables (in a function, not global) handled? Is that memory stored on the heap instead?
It is stored elsewhere, in the memory location set aside for global and static data. "Heap" and "stack" (heap/freestore for dynamic allocations, stack for local allocations) are just semantic names we assign to particular regions of memory that tend to be used for and treated the same way. To the code, it's all one big 32- or 64-bit address space that the OS has (hopefully) virtualized for us, and it all maps down to the real 32-or-61-bit address space of the physical RAM.
Quote:
And if stack memory is around a meg, aren't you in danger of of running out of stack space when using recursion(assuming whatever you're recursing is going to be doing a WHOLE bunch of recursing)?
Yes.
Quote:
Is this how it actually works though?
In C++? Pretty much. The standard doesn't actually stipulate how dynamic memory allocation takes place, but most implementations involve some kind of walk through lists or other data structures in order to find an available free block of appropriate size. Compare this to C#, where the same operation is generally little more than an addition operation. All languages differ, but its fairly common in C and C++ that "dynamic allocation is not superfast."
On the other hand, it's not cripplingly slow, either, and you should not pre-emptively avoid dynamic allocation on the misguided assumption that its too slow.
Quote:
I had a game that suddenly became very very slow to start up. I found this was because a function called many times at start up had a largish array in it. I guessed the speed was due to the memory was being re-allocated.
I moved the array to the global scope. Result game started at normal (near instant) speed. So what happened there?
This really could have been a result of any number of things, so its hard to say. I should also point out that by moving the array like that you completely changed the semantics and behavior of the code -- its entirely possible, for example, that you actually broke something and you only saw speed increases because massive chunks of functionality were no longer executing (I've seen it happen). The fastest code is the code that never executes, after all!
But yeah. Without the code and some analysis, it's pretty much impossible to tell.
Quote:Original post by empirical2Quote:Original post by Evil SteveQuote:Original post by GoishinDynamic memory allocation is generally slow. Allocating memory on the stack is essentially free. It's going through a linked list of allocations, finding a block that's a reasonable size, and possibly allocating memory from the OS versus just changing a register from one value to another.
For that matter, are there pros/cons (other than memory size limitations) I would want memory from one or the other?
Is this how it actually works though?
Pretty much, yes, at least in "low-level" languages like C/C++. And yes, it does get a bit costly, at least compared to stack allocation.
(in .NET it's a different matter. Heap allocations are cheap enough there (Basically just pushing and popping on a stack)
If somebody asked me "how do you allocate memory from the stack?" my first assumption would be that they wanted to see if I knew about alloca. alloca is to the stack as malloc is to the heap.
One downside to using excess stack that hasn't been brought up yet is that depending on how your OS handles stack overflows it can be difficult to properly recover. If malloc fails you my be able to delete a bunch of cache that you don't really need, try again, and go about your business. The same is not necessarily true with the stack because you have to properly reset all the stuff the OS is using to detect when you've gone over the stack limit.
One downside to using excess stack that hasn't been brought up yet is that depending on how your OS handles stack overflows it can be difficult to properly recover. If malloc fails you my be able to delete a bunch of cache that you don't really need, try again, and go about your business. The same is not necessarily true with the stack because you have to properly reset all the stuff the OS is using to detect when you've gone over the stack limit.
Quote:If memory on the stack is returned when a function returns, how are static variables (in a function, not global) handled? Is that memory stored on the heap instead?
You have to remember that static variables are only stored once, global and local statics the same. I don't know exactly where it puts them, but since there is only one instance, the compiler can basically put them anywhere and hard-code their adresses.
Quote:
nd if stack memory is around a meg, aren't you in danger of of running out of stack space when using recursion(assuming whatever you're recursing is going to be doing a WHOLE bunch of recursing)?
yes, but I guess the OS can introduce some reservations to that statement. Swapping out/in pages etc.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement