- Explanation of the Example Program
- Where an Application Starts
- Runtime Internals: Stack and Heap
- The Class "Object"
- Some Light Relief
The stack is a runtime data structure for keeping track of memory to support functions and recursive function invocation. All modern block-structured languages use a stack. Many processors have some hardware support for them.
When you call a method, some housekeeping data, known as an activation record or stack frame, is pushed onto the stack. The activation record contains the return address, the arguments passed to the function, the space for local variables, and so on. When you return from a function, the record is popped from the stack. The next function call will push another record into the same space.
If you have any pointers back into the old activation record on the stack, memory can be corrupted, a common problem in C/C++. In other words, the lifetime of stack-based storage is tied to the scope in which it was allocated, and although some languages let you get this wrong, Java doesn't!
The heap is another compiler runtime data structure. It is a large storage area that is managed dynamically. Many programming languages support heap-based memory allocation. Different pieces of storage can be allocated from and returned to the heap in no particular order. Whenever something is allocated on the heap, its lifetime is independent of the scope in which is was allocated.
Fruit saveIt; void foo() { Fruit f = new Fruit(); saveIt = f; } ... foo(); saveIt.grams = 23; // is it valid? f was allocated in foo // and foo is no longer live
In the code above, a Fruit object is allocated in a method and a reference to that Fruit is stashed away for later use. Later, after the method has returned, the reference is used to access the Fruit. This is valid for heap-based storage. It is not valid in stack-based storage and is the source of a large number of high-profile bugs and failings in C/C++ code. The Internet Worm of 1988 used this flaw to subvert a system. Ten years later, the Hotmail bug of 1998 fell vulnerable to the same flaw! Since Java uses only heap-based storage for variables accessed through references, objects can happily live on after the scope in which they were created.
Figure 3-1. Stacks in Java.
Since the heap and the stack both grow dynamically on demand, they are usually put at opposite ends of the address space and grow into the hole between them.
Looking for an Argument?
Here is a little bit of compiler terminology, common to most languages.
A parameter is a variable declared in a method declaration. It provides a name for referring to the different arguments with which the method will later be called. In the following code, the variables param1 and param2 are parameters:
void foo(int param1, char param2) { param 1 = ... ; ... = param2; }
Some people call a parameter a formal parameter.
Notice how the String array parameter to the main routine is usually called "arg" even though it is a parameter, not an argument. This is a carryover from the same mistaken convention in C.
An argument is a value used in a particular call to a method. In the following code the values 23 and c are arguments:
plum.foo( 23, c );
Some people call an argument, an actual parameter.