Академический Документы
Профессиональный Документы
Культура Документы
David Walker
CS 320
Today:
Mark-sweep collection (Appel 13.1)
Conservative collection
Compiler interface (13.7)
Mark-sweep
A two-phase algorithm
Mark phase: Depth first traversal of object
graph from the roots to mark live data
Sweep phase: iterate over entire heap,
adding the unmarked data back onto the free
list
Example
r1
Free list
In use
On free list
Example
Mark Phase: mark nodes reachable from roots
r1
Free list
In use
On free list
Marked
Example
Mark Phase: mark nodes reachable from roots
r1
Free list
In use
On free list
Marked
Example
Mark Phase: mark nodes reachable from roots
r1
Free list
In use
On free list
Marked
Example
Sweep Phase: set up sweep pointer; begin sweep
p
Free list
r1
In use
On free list
Marked
Example
Sweep Phase: add unmarked blocks to free list
p
Free list
r1
In use
On free list
Marked
Example
Sweep Phase
p
Free list
r1
In use
On free list
Marked
Example
Sweep Phase: retain & unmark marked blocks
p
Free list
r1
In use
On free list
Marked
Example
Sweep Phase
p
Free list
r1
In use
On free list
Marked
Example
Sweep Phase: GC complete when heap boundary
encountered; resume program
Free list
r1
In use
On free list
Marked
Amortized analysis
Each collection returns H - R words
For every allocated word, we have GC cost:
((c1 * R) + (c2 * H)) / (H - R)
A Hidden Cost
Depth-first search is usually implemented
as a recursive algorithm
Uses stack space proportional to the longest
path in the graph of reachable objects
one activation record/node in the path
activation records are big
A nifty trick
Deutsch-Schorr-Waite pointer reversal
Rather using a recursive algorithm, reuse the
components of the graph you are traversing to
build an explicit stack
This implementation trick only demands a few
extra bits/block rather than an entire activation
record/block
We already needed a few extra bits per block
to hold the mark anyway
DSW Algorithm
back
next
DSW Algorithm
back
next
back
next
DSW Algorithm
back
next
back
back
next
next
DSW Algorithm
back
next
back
next
back
back
next
next
DSW Algorithm
back
next
back
next
back
back
next
next
extra bits needed to keep track of which
record fields we have processed so far
DSW Setup
Extra space required for sweep:
1 bit/record to keep track of whether the record has
been seen (the mark bit)
f log 2 bits/record where f is the number of fields in
the record to keep track of how many fields have
been processed
assume a vector: done[x]
Functions:
DSW Algorithm
fun dfs(next) =
if (pointer next) &
not (marked next) then
(* depth-first search in
constant space *)
(* initialization *)
while true do
i = done[next]
if i < (fields next) then
(* process ith field *)
else
(* back-track to previous
record *)
DSW Algorithm
fun dfs(next) =
if (pointer next) &
not (marked next) then
(* depth-first search in
constant space *)
(* initialization *)
while true do
i = done[next]
if i < (fields next) then
(* process ith field *)
else
(* back-track to previous
record *)
back = nil;
mark next;
done[next] = 0;
DSW Algorithm
fun dfs(next) =
if (pointer next) &
not (marked next) then
(* initialization *)
while true do
i = done[next]
if i < (fields next) then
(* process ith field *)
else
(* back-track to previous
record *)
(* depth-first search in
constant space *)
y = next.i
if (pointer y) & not (marked y) then
next.i = back;
reuse field to
back = next;
store back ptr
next = y;
mark next;
done[next] = 0;
else
done[next] = i + 1
DSW Algorithm
fun dfs(next) =
if (pointer next) &
not (marked next) then
(* initialization *)
while true do
i = done[next]
if i < (fields next) then
(* process ith field *)
else
(* back-track to previous
record *)
(* depth-first search in
constant space *)
y = next.i
if (pointer y) & not (marked y) then
next.i = back;
back = next;
next = y;
initialize for
mark next;
done[next] = 0; next iteration
else
done[next] = i + 1
DSW Algorithm
fun dfs(next) =
if (pointer next) &
not (marked next) then
(* initialization *)
while true do
i = done[next]
if i < (fields next) then
(* process ith field *)
else
(* back-track to previous
record *)
(* depth-first search in
constant space *)
y = next.i
if (pointer y) & not (marked y) then
next.i = back;
back = next;
next = y;
mark next;
done[next] = 0;
else
done[next] = i + 1 field is done
DSW Algorithm
fun dfs(next) =
if (pointer next) &
not (marked next) then
(* depth-first search in
constant space *)
dfs complete
(* initialization *)
while true do
i = done[next]
if i < (fields next) then
(* process ith field *)
else
(* back-track to previous
record *)
y = next;
next = back;
if next = nil then return;
i = done[next];
back = next.i;
next.i = y;
done[next] = i + 1;
DSW Algorithm
fun dfs(next) =
if (pointer next) &
not (marked next) then
(* depth-first search in
constant space *)
(* initialization *)
while true do
i = done[next]
if i < (fields next) then
(* process ith field *)
else
(* back-track to previous
record *)
y = next;
next = back;
if next = nil then return;
i = done[next];
back = next.i;
next.i = y;
done[next] = i + 1;
advance to
next field
More Mark-Sweep
Mark-sweep collectors can benefit from the
tricks used to implement malloc/free efficiently
multiple free lists, one size of block/list
Conservative Collection
Even languages like C can benefit from GC
Boehm-Weiser-Demers conservative GC uses
heuristics to determine which objects are pointers and
which are integers without any language support
Compiler Interface
The interface to the garbage collector involves
two main parts
allocation code
languages can allocated up to approx 1 word/7 instructions
allocation code must be blazingly fast!
should be inlined and optimized to avoid call-return overhead
gc code
to call gc code, the program must identify the roots
to traverse data, heap layout must be specified somehow
Allocation Code
Assume size of record allocated is N:
1.
2.
3.
4.
5.
6.
7.
8.
Allocation Code
Assume size of record allocated is N:
1.
2.
3.
4.
5.
6.
7.
8.
Allocation Code
Assume size of record allocated is N:
1.
2.
3.
4.
5.
6.
7.
8.
Allocation Code
Assume size of record allocated is N:
1.
2.
3.
4.
5.
6.
7.
8.
Allocation Code
Assume size of record allocated is N:
1.
2.
3.
4.
5.
6.
7.
8.
Allocation Code
Assume size of record allocated is N:
1.
2.
3.
4.
5.
6.
7.
8.
Calling GC code
To call the GC, program must:
identify the roots:
a GC-point, is an control-flow point where the
garbage collector may be called
allocation point; function call
Calling GC code
To call the GC, program must:
enable GC to determine data layout of all
objects in the heap
for ML, Tiger, Pascal:
every record has a header with size and pointer info
Summary
Garbage collectors are a complex and
fascinating part of any modern language
implementation
Different collection algs have pros/cons
explicit MM, reference counting, copying,
generational, mark-sweep
all methods, including explicit MM have costs
optimizations make allocation fast, GC time, space
and latency requirements acceptable
read Appel Chapter 13 and be able to analyze,
compare and contrast different GC mechanisms