16

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:

Stack

The stack is cleared upon exiting the method, but what does that mean? Is the pointer at the stack just moved back to the start of the stack making it empty? I hope this is not too broad of a question. I am not really sure what is going on behind the scenes when the stack is cleared from exiting a method.

Community
  • 1
  • 1
Evorlor
  • 7,263
  • 17
  • 70
  • 141
  • 1
    https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.6 – fabian Apr 30 '15 at 14:16
  • When the method ends, that block of stack memory reserved to that method becomes empty because is not needed anymore (function ended) and the stack pointer jumps back to the previous stack block (in order to proceed with the previous function you were dealing). – Filipe Paulo Apr 30 '15 at 14:24
  • Check out this 17 years old article about [How the Java virtual machine handles method invocation and return](http://www.javaworld.com/article/2076949/learn-java/how-the-java-virtual-machine-handles-method-invocation-and-return.html). It explains in-depth what happens on method invocation and return. The JVM basics shouldn't have changed that much throughout time. You can cross-check with the above linked specification if you got the time ... – MicSim Apr 30 '15 at 14:33
  • 1
    It's up to the JVM how to implement it. You could talk about how its conceptually done, but how it's really done is something that can change between JVM's and versions of JVM's. (For example, conceptually all objects are allocated on the heap. But in reality, if an object is never referenced outside a method, the HotSpot JIT compiler can decide to allocate it on the stack instead; however in your code you'll never notice the difference) – Erwin Bolwidt May 01 '15 at 02:53

6 Answers6

4

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.

Zippy
  • 3,826
  • 5
  • 43
  • 96
al-eax
  • 712
  • 5
  • 13
1

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 :

  • semantically the variables go out of scope and can no longer be used
  • in the hard way, the stack pointer is rewinded, effectively freeing the memory : it will be useable by next function call

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.

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
1

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...

traveh
  • 2,700
  • 3
  • 27
  • 44
1

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.

1

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.

MariotoA
  • 76
  • 4
1

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.)

David Hoelzer
  • 15,862
  • 4
  • 48
  • 67