Now let's run through the same program that we did for the run-time stack and see how all of our memory model is affected. For reference, the program is below:
public class Student { public void PayFees() { feesOwing = 0; } private String name; private int age; private String courses; private double feesOwing = 5000.00; private boolean scholarship; } public class SecondProg { public static void main(String[] args) { Student s1 = new Student(); s1.PayFees(); } }
This is what the memory model looks like before any lines of the program have been executed:
The run-time stack appears exactly as it did before. However, we now have some memory that has been allocated in static space. In this memory is the information necessary to allocate an object of this class (specifically the data types of all the member variables and the definitions of all methods. The method definition has been omitted in order to save space in the diagram) This memory in static space is automatically allocated by instructions that were issued by the compiler at compile-time. (Remember -- we're talking about the run-time memory in these diagrams) These instructions were issued by the compiler as a result of our class definition.
After the first line has been executed, the memory model looks like this:
Note that we have declared a local variable here (s1) which contains a reference to the newly created object. The value of s1 (i.e. the reference to the object) is stored in the run-time stack. The object itself, however, was allocated memory in object space. Note that the reference stored in the stack frame corresponds to the 'address' of the object. This is how we can use the symbol s1 and have it refer to the memory occupied by the object. Note also that the line about to be executed has been incremented to 2.
Now we invoke PayFees(), and the run-time stack changes accordingly. Before any line of this method executes, the memory model will look like this:
Just to refresh your memory, the method PayFees() is defined as follows
public void PayFees() { feesOwing = 0; }
After the first line of PayFees() has been executed, we have:
This is where we change the memory associated with our object s1: the instance variable feesOwing is set to 0.
The next thing that happens is that we finish executing the method PayFees:
The frame for PayFees() is deleted as before.
Now that we've finished the method PayFees() we are also at the end of the method main. The frame is deleted, as before, and all the memory is released as the program has finished.
This is roughly how the memory model works.