Call stack
Call Stack Overview
Also known as runtime stack, execution stack, or program stack.
Special data structure used during program execution.
Stores information about active subroutines/methods.
Follows Last In First Out (LIFO) principle—last pushed is the first popped.
Purpose of the Call Stack
Primarily used to store stack frames which include:
Return address: Where to return after a method execution.
Method parameters: Input values for the method being invoked.
Local variables: Variables with limited scope, exist only during method execution.
Stack Frames
Each method creates a unique stack frame when invoked.
The frame contains:
Method’s local variables, parameters, and return address.
Stack frame is pushed to the call stack when a method is called and popped when the method finishes.
Example Flow of Execution
Program starts with the main method which can call other methods (A, B, C, D, E).
Execution of methods is non-sequential, based on calls:
Example Call Tree:
main calls A, B
A calls C
C calls D, E
Visualization of execution:
At various points, as methods are invoked, corresponding call frames are pushed onto the stack.
Runtime Stack Management
Pushing Call Frames:
When a method is invoked, it's frame is added to the stack. For instance:
Start at main.
Push frame for A when called by main.
Push frame for C when A calls C.
Popping Call Frames:
After a method finishes, its frame is removed from the stack, returning to the previous method's frame.
Error Handling with Call Stack
If an error occurs in a method (e.g., method D):
The stack displays the sequence of method calls leading to the error:
e.g., main → A → C → E → D.
This helps identify where the error originated and the state of the program at that time.
Finalizing Method Execution
After finishing a method, its stack frame is popped, allowing the program to resume correctly from where it left off:
Finish method D --> pop D
Continue in C --> pop C after completion
Finally return to main and process other methods (like B).
Conclusion
The call stack is crucial for managing method execution flow in programming:
Keeps track of which method is currently running.
Contains context for each method, including local variables.
Useful in debugging to trace back through method calls and variable states.
Enables identification of errors by showing the chain of method calls.