I was reading What and where are the stack and heap?. One thing I am a bit fuzzy on is what happens to the stack after a method exits. Take this image for example:
Keep in mind the stack is a zone in memory assigned to a process.
In summary, when in your code you call a function (tipically in assembly language), you need to store in memory the registers you're going to use (it could vary if you're following another contract) because these registers could be overwriten by calls to another function (you'd need to the store return address, arguments, and a lot more, but let's omite that). To do that you decrease the stack pointer by that number of registers. Before to exit, you need to make sure you increase the stack pointer by that same number. You don't need to do anything more because the values you were storing are not needed anymore, they will be overwrited by the next function call.
In Java, references to objects are in the stack when the object itself is in the heap. If all the references to an object are removed from the stack, the garbage collector will remove the object from heap.
I hope my answer helps you. Also, check this.
It might be useful for you to think about what your compiled code might look like at a machine (or, better for us humans, assembly) level. Consider this as a possible example in X86 Assembly:
When the method is called, arguments will either be passed in the registers or passed on the stack itself. Either way, the code calling the method will eventually:
call the_method
When this happens, the current instruction pointer is pushed onto the stack. The stack pointer is pointing at it. Now we're in the function:
the_method:
push ebp
mov ebp, esp
The current base pointer is preserved on the stack and the base pointer is then used to reference things in the stack (like passed in variables).
sub esp, 8
Next, 8 bytes (assuming two four byte integers are allocated) are allocated on the stack.
mov [ebp-4], 4
mov [ebp-8], 2
The local variables are assigned. This could actually be accomplished by simply pushing them but more likely there will be a sub
involved. Fast forward to the end:
mov esp, ebp
pop ebp
ret
When this happens, the stack pointer is right back where it was when we started, pointing at the stored base pointer (saved frame pointer). This is popped back into EBP leaving ESP pointing at the return pointer which is then "popped" into EIP with the ret
. Effectively, the stack has unwound. Even though the actual memory locations haven't changed for the two local variables, they are effectively above the stack (physically below in memory, but I think you get what I mean.)
When a method is called, local variables are located on the stack. Object references are also stored on the stack, corresponding objects are store in the heap.
The stack is just a region of memory, it has a start and end address. The JVM (java virtual machine) has a register which points to the current top of the stack (stack pointer). If a new method is called, an offset will be added to the register to get new space on the stack.
When a method call is over, the stack pointer will be decreased by this offset, this frees the allocated space.
Local variables and other stuff (like return address, parameters...) may still on the stack and will be overwritten by next method call.
BTW: this is why java stored all objects in heap. When an object would be located on the stack, and you would return the reference which points to the stack, the object could be destroyed by next method call.
A stack is just that, a stack of things, usually a stack of frames, with the frames containing parameters, local variables and instances of objects, and some other things depending on your operating system.
If you have instantiated objects on the stack, i.e. MyClass x and not MyClass * x = new MyClass(), then the object x will be torn down and its destructor called when the stack is rewound to the previous frame, which essentially just makes the current stack pointer(internal) point to the previous frame. In most native languages no memory will be cleared, etc.
Finally this is why you should initialise local variables(in most languages) as a call to the next function will setup a new frame which will most likely be in the same place as the previously rewound stack frame, so your local variables will contain garbage.
Is the pointer at the stack just moved back to the start of the stack making it empty?
the pointer at the stack is moved back to where it was before the function call. The stack would not be empty because it contains data that belongs to calls that brought the program to that point.
To illustrate: if func1 called func2 called func3 the stack will look something like this:
func1 args/local vars... | func2 args/local vars... | func3 args/local vars...
After func3 returns it will be:
func1 args/local vars... | func2 args/local vars...
During execution of a function, all local variables are created in the stack. That means that the stack grows to make enough room for those variables.
When the function ends, all the local variables goes out of scope and the stack is rewinded. Nothing else needs to happen, no implicit zeroing memory. But :
Above is not only true for functions but can be the same for any block of code since semantically the variables defined in the block go out of scope at end of block.