Chapter 7 Objects and Memory
Chapter 7 Objects and Memory
Structure of memory
The fundamental unit of memory is called a bit, either 0 or 1. In most modern architectures, the smallest unit on which the hardware operates is a sequence of eight consecutive bits called byte. a binary (executable) file 0 1 2 3 010110011000010010011110110000011... Numbers and instructions are stored in still larger units. The most common integer size on a particular hardware is called a word. Because machines have different architectures, the number of bytes and the order of bytes in a word may vary from machine to machine.
Heap-stack diagrams
It is easier to understand how Java works if you have a good mental model of its use of memory. Whenever your program creates a new object, you need to add a block of memory to the heap. That block must be large enough to store the instance variables for the object, along with some extra space called overhead, that is required for any object. Whenever your program calls a method, you need to create a new stack frame by adding a block of memory to the stack region. The stack frame must be large enough to store local variables for the method, along with some overhead. When a method returns, Java reclaims the memory in its frame.
Object references
Internally, Java identifies an object by its address in memory. That address is called a reference. As an example, when Java evaluates the declaration
Rational a = new Rational(1, 2)
it allocates heap space for the new Rational object. For this example, imagine that the object is allocated at address 1000. The local variable a is allocated in the current stack frame and is assigned the value (address), which identifies the object.
heap
Address model
a.num a.den 1 2
1000
1020
public void run() { Rational a = new Rational(1, 2); Rational b = new Rational(1, 3); Rational c = new Rational(1, 6); Rational sum = (a.add(b)).add(c); } b.num b.den 1 3
1040
c.num 1 6 FFB4 1040 FFB8 FFBC FFC0 stack
c.den
sum c
b
a
1020
1000
heap
Pointer model
a.num a.den 1 2
public void run() { Rational a = new Rational(1, 2); Rational b = new Rational(1, 3); Rational c = new Rational(1, 6); Rational sum = (a.add(b)).add(c); }
b.num b.den
1 3
c.num
1 6
c.den
sum c
b
a stack
heap
public void run() { Rational a = new Rational(1, 2); Rational b = new Rational(1, 3); Rational c = new Rational(1, 6); Rational sum = (a.add(b)).add(c); }
public Rational add(Rational r) { return new Rational(this.num*r.den + r.num*this.den, this.den*r.den); }
r this
1020 1000
FFA8 FFAC
c.den
sum
c b a 1040 1020 1000
FFB4
FFB8 FFBC FFC0
stack
heap
public void run() { Rational a = new Rational(1, 2); Rational b = new Rational(1, 3); Rational c = new Rational(1, 6); Rational sum = (a.add(b)).add(c); }
public Rational add(Rational r) { return new Rational(this.num*r.den + r.num*this.den, this.den*r.den); }
3 1040
c.num
1 6 1060
c.den
sum
c b a 1040 1020 1000
FFB4
FFB8 FFBC FFC0 stack
(a.add(b)).num (a.add(b)).den
5 6
heap
public void run() { Rational a = new Rational(1, 2); Rational b = new Rational(1, 3); Rational c = new Rational(1, 6); Rational sum = (a.add(b)).add(c); }
public Rational add(Rational r) { return new Rational(this.num*r.den + r.num*this.den, this.den*r.den); }
r this
1040 1060
FFA8 FFAC
c.den
sum
c b a 1040 1020 1000
FFB4
FFB8 FFBC FFC0 stack
5 6 1080
(a.add(b)).add(c).num (a.add(b)).add(c).den
1
1
heap
public void run() { Rational a = new Rational(1, 2); Rational b = new Rational(1, 3); Rational c = new Rational(1, 6); Rational sum = (a.add(b)).add(c); }
public Rational add(Rational r) { return new Rational(this.num*r.den + r.num*this.den, this.den*r.den); }
c.den
sum
1080
1040 1020 1000
FFB4
FFB8 FFBC FFC0 stack
(a.add(b)).num (a.add(b)).den
5 6 1080
c b a
(a.add(b)).add(c).num (a.add(b)).add(c).den
1
1
heap
public void run() { Rational a = new Rational(1, 2); Rational b = new Rational(1, 3); Rational c = new Rational(1, 6); Rational sum = (a.add(b)).add(c); }
public Rational add(Rational r) { return new Rational(this.num*r.den + r.num*this.den, this.den*r.den); }
c.den
sum
1080
1040 1020 1000
FFB4
FFB8 FFBC FFC0 stack
(a.add(b)).num (a.add(b)).den
5 6 1080
c b a
(a.add(b)).add(c).num (a.add(b)).add(c).den
1
1
Garbage collection
In the previous example, the object a.add(b) was created in the intermediate step but not referenced by the final stack. It is now garbage. When memory is running short, Java does garbage collection
Mark the objects referenced by variables on stack or in static storage. Sweep all objects in the heap, reclaim unmarked objects (garbage).
Draw a heap-stack diagram (pointer model) showing the state of memory just before the run() method returns.
When you pass an argument of a primitive type to a method, Java copies the value of the argument into the parameter variable. As a result, changes to the parameter variable have no effect on the argument.
n x
17 17
FFC0 FFC8
EmbeddedInteger class
public class EnbeddedInteger { public EmbeddedInteger(int n) { value = n; } public void setValue(int n) { value = n; } public int getValue() { return value; } public String toString() { return + value; } private int value; }
Object
public void run() { EmbeddedInteger x = new EmbeddedInteger(17); increment(x); println(x = + x); } private void increment(EmbeddedInteger n) { n.setValue(n.getValue() + 1); println(n = + n); } Output n = 18 n = 18
stack
1000 FFC0
1000
x.value 17
1000
FFC8
Wrapper classes
byte short int long float double boolean char Byte Short Integer Long Float Double Boolean Character