Garbage Collection
Garbage: Example
1: var f = 0;
2: {
3: var x = 1;
4: f = fun(y) {
5: print(x);
6: x = x + 1;
7: };
8: }
9: f(1);
10: f(2);
Line | FP (a) | Heap (h) |
1 | 200 | { 100 : 0, 200: {p : 0, f : 100}} |
3 | 208 | { 100 : 0, 108 : 1, 200 : {p : 0, f : 100}, 208 : {p : 200, x : 108} } |
7 | 208 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 200 : {p : 0, f : 116}, 208 : {p : 200, x : 108} } |
8 | 200 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 200 : {p : 0, f : 116}, 208 : {p : 200, x : 108} } |
9 | 200 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 124: 2, 200 : {p : 0, f : 116}, 208 : {p : 200, x : 124} , 216 : {p : 208} } |
10 | 200 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 124: 2, 132:3, 200 : {p : 0, f : 116}, 208 : {p : 200, x : 132}, 216 : {p : 208}, 224 : {p : 208} } |
Garbage: Example
1: var f = 0;
2: {
3: var x = 1;
4: f = fun(y) {
5: print(x);
6: x = x + 1;
7: };
8: }
9: f(1);
10: f(2);
Line | FP (a) | Heap (h) |
1 | 200 | { 100 : 0, 200: {p : 0, f : 100}} |
3 | 208 | { 100 : 0, 108 : 1, 200 : {p : 0, f : 100}, 208 : {p : 200, x : 108} } |
7 | 208 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 200 : {p : 0, f : 116}, 208 : {p : 200, x : 108} } |
8 | 200 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 200 : {p : 0, f : 116}, 208 : {p : 200, x : 108} } |
9 | 200 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 124: 2, 200 : {p : 0, f : 116}, 208 : {p : 200, x : 124} , 216 : {p : 208} } |
10 | 200 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 124: 2, 132:3, 200 : {p : 0, f : 116}, 208 : {p : 200, x : 132}, 216 : {p : 208}, 224 : {p : 208} } |
Garbage Collection
Garbage Collection
Reference Counting
Example
x = 5;
y = 7;
z = x;
y = z;
5
7
c=1
c=1
x
y
z
None
c=1
c=2
c=4
c=3
c=2
c=3
c=0
Deallocate
Reference Counting: Challenges
Cycles
x = {next: None} // object O1
y = {next: x } // object O2
x.next = y;
x = 0;
y = x;
Cycles
x = {next: None} // object O1
y = {next: x } // object O2
x.next = y;
x = 0;
y = x;
x
y
0
c=2
next:
c = 1
next:
c = 1
data:
c = 1
data:
c = 1
Mark and Sweep
Mark
Garbage: Example
1: var f = 0;
2: {
3: var x = 1;
4: f = fun(y) {
5: print(x);
6: x = x + 1;
7: };
8: }
9: f(1);
10: f(2);
Line | FP (a) | Heap (h) |
1 | 200 | { 100 : 0, 200: {p : 0, f : 100}} |
3 | 208 | { 100 : 0, 108 : 1, 200 : {p : 0, f : 100}, 208 : {p : 200, x : 108} } |
7 | 208 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 200 : {p : 0, f : 116}, 208 : {p : 200, x : 108} } |
8 | 200 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 200 : {p : 0, f : 116}, 208 : {p : 200, x : 108} } |
9 | 200 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 124: 2, 200 : {p : 0, f : 116}, 208 : {p : 200, x : 124} , 216 : {p : 208} } |
10 | 200 | { 100 : 0, 108 : 1, 116 : (208, y, {print(x); x = x + 1} ), 124: 2, 132:3, 200 : {p : 0, f : 116}, 208 : {p : 200, x : 132}, 216 : {p : 208}, 224 : {p : 208} } |
End�
OK, it’s a little more complicated
Reference counting: Load and Store
store_local i
x = old object pointed to by variable i.
x.count -=1;
y = object popped from stack;
store object y to variable i
if( x.count == 0)
deallocate x;
store_local i
y = value object popped from stack;
store value object y to variable i
Without garbage collection
With reference counting
load_local i
x = read value object read from variable i
push x to the stack
load_local i
x = read value object read from variable i
x.count += 1
push x to the stack
Why do we not increment y.count?
MITScript VM
Globals |
f |
Locals |
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
IP |
7 |
Heap
Stack
Frame
Closure { f : , ctx : [ ]}
Op Stack |
|
|
Locals |
y : 1 |
x : None |
IP |
0 |
Stack
Frame
Op Stack |
|
|
1 |
MITScript VM
Globals |
f |
Locals |
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
IP |
7 |
Heap
Stack
Frame
Closure { f : , ctx : [ ]}
Op Stack |
|
1 |
Locals |
y : 1 |
x : None |
IP |
1 |
Stack
Frame
Op Stack |
|
|
1 |
MITScript VM
Globals |
f |
Locals |
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
IP |
7 |
Heap
Stack
Frame
Closure { f : , ctx : [ ]}
Op Stack |
1 |
2 |
Locals |
y : 1 |
x : None |
IP |
2 |
Stack
Frame
Op Stack |
|
|
1 |
MITScript VM
Globals |
f |
Locals |
function {
functions = [ ],
constants = [None, 0, 1],
names = [f],
instructions = [
load_const 1
load_func 0
alloc_closure
store_global 0
load_global 0
load_const 2
call 1
pop
load_const 0
return
]}
function {
local_vars = [y, x],
constants = [None, 2],
instructions = [
load_local 0
load_const 1
add
store_local 1
load_const 0
return
]
}
IP |
7 |
Heap
Stack
Frame
Closure { f : , ctx : [ ]}
Op Stack |
|
3 |
Locals |
y : 1 |
x : None |
IP |
3 |
Stack
Frame
Op Stack |
|
|
1 |
Reference Counting Arithmetic
add
y = value popped from stack
y.count -=1;
x = value object popped from stack;
x.count -=1;
z = new Integer(x.ival()+y.ival())
z.count = 1
push z onto the stack
if( x.count == 0)
deallocate x;
if( y.count == 0)
deallocate y;
add
y = value popped from stack
x = value object popped from stack;
push new Integer(x.ival()+y.ival())
Without garbage collection
With reference counting