Java Memory Management
Java Memory Management
Static information (interface & class boxes) and instance information (object boxes) are stored in the heap. Method information is stored in the run-time stack.
Static box:
Name of class Math Object Name of superclass
Method frame:
Name of method and currentlyexecuting line number main : 1 Name of class (for static method) or address of object (for instance method) MainClass
Instance:
Memory address Type of object (name of its class) Student
Static space For each class and interface mentioned in the program, draw a memory box in the static space. In each of these memory boxes record: the class/interface name [upper left corner] for a class, the superclass it extends [upper right corner] the list of interfaces (if any) implemented / extended [upper right corner] the names and values of static variables (if any) [in the main area of the box]; this includes all interface constants for a class, the signatures of the static methods (if any) [in the main area of the box]
Only one copy of each class and interface (and their static members) exists no matter how many objects are created. Each variable starts with the default value for its type, unless it has an initializer. Record the values.
Object space
An object is created by a new expression calling a constructor of some class. Draw a new memory box for it in the object space. The object gets a unique address (dierent from all other objects in use), which we make up and write in the upper left corner. Represent the address as an arbitrary four digit hexadecimal number (e.g. ABCD, 0007). Divide the memory box for the object into a stack of boxes: the bottom-most part for the class of the object, and one part for each ancestor of that class. The object gets a copy of the instance members of each of these classes. For each class, write the members in the corresponding part of the memory box and the name of the class in the upper right corner of the part.
Each variable starts with the default value for its type, unless it has an initializer. Record the values. Execute the constructor as if it were an instance method called on the object through a reference of the same type as the object. The constructor starts by executing the code in the superclass default constructor, unless the rst statement specically species how to start: this(...) selects another constructor of the class (based on the argument types) super(...) types) selects a superclass constructor (based on the argument
When the constructor is done, the value of the new expression is the address of the new object.
Special cases with new You can create a String object without saying new. Example: String s = "Wombat"; // Shorthand. String s = new String("Wombat"); // What it means. What about drawing an instance of a class that you didnt write, such as String? You probably dont know what the instance variables are. Yet you need to keep track of the contents of the object somehow. Just make up a sensible notation. The next slide contains a few examples.
10
11
Object
Object
5
C Object M Dont look here! m:1 0000B
3
Object main(String[])
1
main:2 A a 0000 M
0000
4
B
2
m() C Dont look here!
13
14
For a name not following a dot, look for it rst (if its a variable) as a local variable or parameter, then look up through the members the method can directly refer to, until you nd it. Overriding If the name refers to a public instance method, then nding the actual method that runs requires an extra step, due to overriding: look for the bottom-most version in the object. Dotted names: e.name First determine e, and then pretend youre inside e instead of inside the current method. If e is a class name C: act as if youre inside a method of class C. a type C reference to an object: act as if youre in the C part of the object.
15
16
17
this
In a running instance method, the object part it came from is recorded in the scope box as an address and type, and can be referred to as this. One use of this is to force variable lookup to skip the parameters and local variables. Trace the following example . . . public class TestThis { public static void main(String[] args) { (new TestThis()).test(); } private int v = 1; public void test() { int v = 2; System.out.println(this.v); } } this is also used when passing a reference to this object to another method, and when checking whether some reference refers to this object.
18
Casting
Casting changes the type of an expression. We can cast an object reference to the type of any part of the object, or to any interface the parts implement. The main use of casting is at compile time to reassure the compiler that we can do certain things with a reference. But it does have two eects when the program is running: since it changes the type, it changes where lookup starts if the reference refers to an object that doesnt have the part cast to, an exception occurs Keep in mind that casting doesnt change the object in any way. temporarily changes how were referring to it. It just
19
super
In a running instance method, the object part immediately above this can be referred to as super. We could also refer to that part by casting this. So why bother with super? Because super has a special behaviour: it prevents overriding (and is the one exception to our member lookup rules). Its often used inside an overriding method to include the behaviour of the overriden method. Trace the following example . . .
20
super Example
public class TestSuper { public static void main(String[] args) { (new Sub()).m1(); System.out.println("---"); (new Sub()).m2(); } } class Super { void m1() { System.out.println("Super!"); } } class Sub extends Super { void m1() { super.m1(); System.out.println("And Sub!"); } void m2() { ((Super)this).m1(); } }
21
Variables
Local variable declaration: Type var; In the current method frame, write the variable name and draw a box to hold the value. Assignment: var = rhs; 1. Evaluate the right side. 2. Find the target of the variable on the left side. 3. Write the value of the right side in the box for the variable. Initialization: Type var = rhs; Do the declaration and then the assignment (as above).
22
Here are the method stack and static boxes for this program, after line 2 of printTwice has nished, but before line 3 begins. (The object referred to by args is not shown.) Stack:
printTwice:3 Test i 1 main:1 args 0000 Test Test
Static space:
Object String Object printTwice() main(String[]) String[] Object length 0 23 valueOf(double) valueOf(int) ...
A simple method call class Simple { public static int zonkest(int one, int two) { if (one > 0 && one < two) { return one; } else { return two; } } public static void main(String[] args){ int i = 7; int j = 4; int k = -2; int l = zonkest( (i+j)/k, j*k ); } } A very complex method call zonkest(Math.max(s.length(), t.length()+1), ((String)(v.elements().nextElement())) .length() );
24
Method call
Arguments 1. Evaluate them in order: inside out, left to right. 2. Put their values into boxes on top of the stack: theyll be picked up by the method as parameters. Executing the method 1. Find the target of the method. 2. Draw a frame for the method on top of the stack, including the argument boxes that will already be there. 3. Write the method name in the upper left corner, and where the method was found (address + part, or class) in the upper right corner. 4. Name the argument boxes to their corresponding paramater names. 5. Indicate the line number about to be executed, by writing :1 after the method name. 6. Execute the body of the method line by line, incrementing the line number each time a line is nished. Returning: return expr; 1. Evaluate expr and replace the current method frame with the value. 2. If the value is being used as an argument, then its ready to be picked up. Otherwise, use it and remove it.
25
Simplications
When tracing, simplications such as these are acceptable: If a class contains nothing static, omit its static box. When drawing an object, include boxes for only those ancestor classes that you wrote yourself. (For example, you can always omit Object unless its used by your code). Make simplications only where you are condent about the code. In the places where you are unsure, include all the detail.
26
Practice
Trace this.
public class TestFrac { public static void main(String[] args) { Frac f1 = new Frac(3, 4); Frac f2 = new Frac(2, 3); Frac f3 = new Frac(1, 2); Frac f4 = Frac.max(f1, Frac.max(f2, f3)); } } public class Frac { private int numer, denom; private static int numCreated; public Frac(int n, int d) { numer = n; denom = d; numCreated++; }
public static Frac max(Frac a, Frac b) { int aSize = a.numer*b.denom; int bSize = b.numer*a.denom; if (aSize > bSize) return a; else return b; } public Frac mult(Frac f) { { return new Frac( this.numer * f.numer, this.denom * f.denom); } public String toString() { return numer + "/" + denom; } 27 }
Frac
Object
int numCreated 3 Frac max() Test void main() main:4 Frac f1 0000 Frac f2 0001 Frac f3 0010 Frac f4 ? Test 0000 int numer 3 int denom 4 Frac mult() . . . 0010 int numer 1 int denom 2 Frac mult() . . . Frac Frac 0001 int numer 2 int denom 3 Frac mult() . . . Frac Object
28
Frac
Object
int numCreated 3 Frac max() max:3 int aSize 4 int bSize 3 b: 0010 a: 0001 0000 main:4 Frac f1 0000 Frac f2 0001 Frac f3 0010 Frac f4 ? 0010 int numer 1 int denom 2 Frac mult() . . . Frac Test Frac Test void main() Object
Frac
Frac
29
Frac
Object
int numCreated 3 Frac max() max:3 int aSize 9 int bSize 8 b: 0001 a: 0000 main:4 Frac f1 0000 Frac f2 0001 Frac f3 0010 Frac f4 ? 0000 Test int numer 3 int denom 4 Frac mult() . . . 0010 int numer 1 int denom 2 Frac mult() . . . Frac Frac 0001 int numer 2 int denom 3 Frac mult() . . . Frac Frac Test void main() Object
30
Frac
Object
int numCreated 3 Frac max() Test void main() main:4 Frac f1 0000 Frac f2 0001 Frac f3 0010 Frac f4 0000 Test 0000 int numer 3 int denom 4 Frac mult() . . . 0010 int numer 1 int denom 2 Frac mult() . . . Frac Frac 0001 int numer 2 int denom 3 Frac mult() . . . Frac Object
31
More Practice
class A { class B extends A { public static int k; public static int k; public int i; public int i; public void m(int i) public void f() { { this.i = i; System.out.println("B" + i); f(); } } public void f() } { System.out.println("A" + i); } } public class Test { public static void main(String[] args) { A a = new A(); B b = new B(); A ab = new B(); a.m(3); b.m(5); ab.m(-2); a.k = 12; ab.k = 15; b.k = 4; ((A)b).k = 8; ((B)ab).k = 4; ((B)a).k = 1; } }
32