0% found this document useful (0 votes)
126 views102 pages

02 GarbageCollection

The document describes garbage collection techniques, including reference counting, mark and sweep, and variants like mark and compact. Reference counting tracks the number of references to each object and reclaims objects with zero references. Mark and sweep first marks all reachable objects from root pointers and then sweeps through the heap to reclaim unmarked objects. Variants like mark and compact also compact the heap to reduce fragmentation.

Uploaded by

draganmatke
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
126 views102 pages

02 GarbageCollection

The document describes garbage collection techniques, including reference counting, mark and sweep, and variants like mark and compact. Reference counting tracks the number of references to each object and reclaims objects with zero references. Mark and sweep first marks all reachable objects from root pointers and then sweeps through the heap to reclaim unmarked objects. Variants like mark and compact also compact the heap to reduce fragmentation.

Uploaded by

draganmatke
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 102

2.

Garbage Collection
2.1 Motivation
2.2 Basic techniques
2.2.1 Reference Counting
2.2.2 Mark & Sweep
2.2.3 Stop & Copy

2.3

Variants
2.3.1 Mark & Compact
2.3.2 Generation scavenging

2.4

Incremental garbage collection


2.4.1 Tricolor marking
2.4.2 Train algorithm

2.5

Root pointers
2.5.1 Pointer tables
2.5.2 Conservative garbage collection

2.6 Garbage collection in multi-threaded systems


2.7 Finalization
2.8 Case study: Java Hotspot VM
2.9 Case study: .NET
1

Motivation
Manual memory deallocation is error-prone (e.g. in C/C++)
1. deallocation too early
p
q

dealloc(p);

"dangling pointer"
q.f = ...;

destroys some other object


2. deallocation missing
p

"memory leak"
object becomes unreachable
but wastes space

p = ...;

Garbage collection
A block is automatically reclaimed as soon as it is not referenced any more.
p

p
p = q;

not referenced any more


=> reclaimed
+ safe (avoids too early or missing deallocation)
+ convenient (code becomes shorter and more readable)
- slower (run-time system must do bookkeeping about blocks)

first time 1960: Lisp


today in almost all lang.:
Java, C#,
Smalltalk, Eiffel,
Scheme, ...

References (pointers)
When are new references created?
object creation:

p = new Person();

p
assignment:

q = p;

parameter passing:

foo(p);
void foo(Object r) {...}

q
r

When are references removed?


assignment:

p = s;

death of local pointers


at the end of a method:

void foo(Object p) {
...
}

reclamation of an object
that contains pointers:

p = null;

Garbage collection & object-orientation


Why is GC especially important in object-oriented languages?
Due to information hiding one never knows by how many pointers an object is referenced.

Example
A a = new A();
B b = new B(a);

How many pointers reference the A object?


a
b

class B {
private A p;
public B(A a) { p = a; }
...

The B object has a private pointer to the A object.


Clients of B don't know that because p is private.

Languages with GC
Java, C#, Eiffel, Smalltalk,
Lisp, Scheme, Scala, Oberon, ...

Languages without GC
C, C++, Pascal, Fortran,
Cobol, ...
4

2. Garbage Collection
2.1 Motivation
2.2 Basic techniques
2.2.1 Reference Counting
2.2.2 Mark & Sweep
2.2.3 Stop & Copy

2.3

Variants
2.3.1 Mark & Compact
2.3.2 Generation scavenging

2.4

Incremental garbage collection


2.4.1 Tricolor marking
2.4.2 Train algorithm

2.5

Root pointers
2.5.1 Pointer tables
2.5.2 Conservative garbage collection

2.6 Garbage collection in multi-threaded systems


2.7 Finalization
2.8 Case study: Java Hotspot VM
2.9 Case study: .NET
5

Reference Counting
Oldest garbage collection technique (1960: Lisp)

Idea
Every object has a counter holding the number of pointers that reference this object
count
data
3
count ... hidden counter field

As soon as the counter becomes 0 the object is deallocated

Counter management
Compiler generates code for updating the counters
if (q != null) q.count++;

assignments

p = q;

IncRef(q);
DecRef(p);

parameters & local variables void foo(Object p) {

if (p != null) {
p.count--;
if (p.count == 0) dealloc(p);
}

IncRef(p);

...
DecRef(p);

deallocation of objects

void dealloc(Object p) {
for (all pointers q in *p) DecRef(q);
...
}

p = null;

a.count--;
b.count--;
c.count--;

Strengths
+ Unreferenced blocks are immediately reclaimed
(no delay like in other GC algorithms)
+ GC does not cause major pauses
(GC overhead is evenly distributed over the whole program)
+ GC can be done incrementally
DecRef(p)

background thread

if (p != null) {
p.count--;
if (p.count == 0) worklist.add(p);
}

while (!worklist.empty()) {
p = worklist.remove();
dealloc(p);
}

Weaknesses
- Pointer assignments and parameter passing impose some overhead
(GC costs are proportional to the number of assigments, even if there is no garbage)
- Counters need space in every object (4 bytes)
- Does not work for cyclic data structures!
p

p = null;

a.count--;
b.count--;

these counters never become 0


objects are never deallocated

Possibilities for dealing with cyclic data structures


ignore them (if there is sufficient memory)
require the programmer to break the cycle (b.next = null;)
try to detect the cycles (expensive)

Cycle detection (Lins92)


decRef(p)
p.count--;
if (p.count == 0)
dealloc(p);
else
mark p for lazy garbage collection;

Every node has one of the following colors:


black
white
grey
red

still referenced => keep it


unreferenced => deallocate it
under inspection by the GC
marked to be inspected by the GC

void decRef(Obj p) {
p.count--;
if (p.count == 0) {
p.color = white;
for (all sons q) decRef(q);
dealloc(p);
} else if (p.color != red) {
p.color = red;
gcList.add(p);
}
}

void incRef(Obj p) {
p.count++;
p.color = black;
}

From time to time do a garbage


collection on the mark list
void gc() {
do
p = gcList.remove()
until (p == null || p.color == red);
if (p != null) {
mark(p);
sweep(p);
collectWhite(p);
}
}
10

Cycle detection (continued)


p

Make all referenced objects grey


before mark(p)
void mark(Obj p) {
if (p.color != grey) {
p.color = grey;
for (all sons q) { q.count--; mark(q); }
}
}

p
after mark(p)
0

Make all unreferenced objects white


void sweep(Obj p) {
if (p.color == grey) {
if (p.count == 0) {
p.color = white;
for (all sons q) sweep(q);
} else restore(p);
}
}
void restore(Obj p) {
p.color = black;
for (all sons q) {
q.count++;
if (q.color != black) restore(q);
}
}

p
after sweep(p)
0

deallocate white objects


void collectWhite(Obj p) {
if (p.color == white) {
to break cycles
p.color = grey;
in collectWhite
for (all sons q) collectWhite(q);
dealloc(p);
}
}
11

Where is reference counting used?


In some interpreted languages where run time efficiency is not an issue
Lisp, PHP, ...

For managing references to distributed objects (COM, CORBA, ...)


e.g. COM
obj->AddRef();
obj->Release();

is called automatically by COM if a reference to an object (interface)


is created
must be called by the programmer if a reference is not needed any more

For managing references (links) to files (Unix, ...)


A file must not be deleted if it is still referenced by a link

12

2. Garbage Collection
2.1 Motivation
2.2 Basic techniques
2.2.1 Reference Counting
2.2.2 Mark & Sweep
2.2.3 Stop & Copy

2.3

Variants
2.3.1 Mark & Compact
2.3.2 Generation scavenging

2.4

Incremental garbage collection


2.4.1 Tricolor marking
2.4.2 Train algorithm

2.5

Root pointers
2.5.1 Pointer tables
2.5.2 Conservative garbage collection

2.6 Garbage collection in multi-threaded systems


2.7 Finalization
2.8 Case study: Java Hotspot VM
2.9 Case study: .NET
13

Idea

roots
"live" pointer variables, which are not on the heap
(e.g. local variables)
heap

2 phases start when the heap is exhausted


1. Mark: Mark all objects that can be reached from roots (directly or indirectly)

2. Sweep: Traverse the heap sequentially and reclaim unmarked objects

14

Pros and Contras


Advantages
+ No overhead in assignments and method calls.
Compiler does not have to generate code for managing reference counters.
+ Needs only 1 mark bit per object (instead of a 4 byte counter field)
+ Cyclic data structures are handled correctly

Disadvantages
-

Noticeable pause while the GC runs (problematic for real-time systems)

Unfavorable for large heaps:


- Sweep time is proportional to the heap size.
- Mark time is proportional to the number of live objects

No compaction (heap remains fragmented)

Related objects are often spread over the whole heap (poor cache behavior).

15

Naive implementation
Simplistic assumption
all objects have the same type

class Block {
boolean marked;
Block left, right;
... // data
}

Mark algorithm
1

recursive depth-first traversal


void mark (Block p) {
if (p != null && !p.marked) {
p.marked = true;
mark(p.left);
mark(p.right);
}
}

5
4

Is this algorithm practical?


No!
Deep recursion might lead to stack overflow
16

Deutsch-Schorr-Waite algorithm
Schorr, Waite: An efficient machine-independent procedure for garbage collection
in various list structures, Communications of the ACM, Aug. 1967

Idea
Pointers are followed iteratively not recursively
The backward path is stored in the pointers themselves!

Example

State while visiting node 5

prev

cur

cur: currently visited node


prev: predecessor of cur;
node in which the backward
chain starts

No connection between cur and prev!


One has to remember, whether the backward chain
starts in left or in right

17

Objects with arbitrary number of pointers


Simplified assumption
all pointers are stored in an array
class Block {
int n;
int i;
Block[] son;
...
}

n
i
son

// number of pointers
// index of currently visited pointer
// pointer array
// data

i == -1
block is still unvisited;
used for marking

4
2

0
1
2
3

already visited
currently under visit
unvisited
data

18

Steps of the DSW algorithm


prev

prev
advance

cur

retreat
prev

cur

when
cur.i == cur.n

cur

p = cur.son[cur.i];
cur.son[cur.i] = prev;
prev = cur;
cur = p;

pointer rotation
p
cur.son[cur.i]

cur
prev

p = cur;
cur = prev;
prev = cur.son[cur.i];
cur.son[cur.i] = p;

pointer rotation
p
cur.son[cur.i]

cur
prev

19

DSW algorithm
void mark (Block cur) {
// assert cur != null && cur.i < 0
Block prev = null;
for (;;) {
cur.i++; // mark
if (cur.i < cur.n) { // advance
Block p = cur.son[cur.i];
if (p != null && p.i < 0) {
cur.son[cur.i] = prev;
prev = cur;
cur = p;
}

mark(p) is called for every root pointer p

Needs only memory for 3 local variables (cur, prev, p)


No recursion
Can traverse arbitrarily complex graphs

} else { // retreat
if (prev == null) return;
Block p = cur;
cur = prev;
prev = cur.son[cur.i];
cur.son[cur.i] = p;
}
}
}
20

Example
prev
cur

advance

prev

advance

retreat
prev

cur

prev
cur

cur

advance

retreat

prev

prev

retreat

prev
cur

advance

prev

cur

cur

cur

retreat

prev
cur

retreat
ready!

21

Type descriptors
Allow pointers to be at arbitrary locations in an object
class Block {
Block x;
Block y;
int data;
Block z;
}
Block a = new Block();
Block b = new Block();

0
4
8
12

tag
x
y
data
z
tag
x
y
data
z

type descriptor
of Block
20

objsize (=20)
0
4
12
sentinel

pointer
offsets

other
information

Every object has a hidden pointer (tag)


to its type descriptor

type descriptors are generated by the compiler for all classes; they are written to the object file
the loader allocates the type descriptors on the heap
new Block() allocates an object and installs in it a pointer to the corresponding type descriptor

22

Type tags
Format of a type tag
31

0
pointer to type descriptor

mark bit (1 = marked)


free bit (1 = free)
Type descriptors are 4 byte aligned (least significant 2 bits are 0)
When GC is not running, the mark and free bits are guaranteed to be 0
When GC is running, the mark and free bits have to be masked out

Pseudo type descriptors for free blocks


are directly stored in the free block
free
list

tag
objsize
next

objsize

In this way the block size of free and used


objects can be uniformly accessed via
tag.objsize.

23

Using the pointer offsets in mark()


Block

type descriptor

size
off
...
...
-16

cur
padr

off

Tag is "abused" for pointing to the offset of the


current son during mark()

16

void mark (Pointer cur) { // assert: cur != null && !cur.marked


prev = null; setMark(cur);
for (;;) {
cur.tag += 4;
off = memory[cur.tag];
if (off >= 0) { // advance
padr = cur + off; p = memory[padr];
if (p != null && !p.marked) {
memory[padr] = prev; prev = cur; cur = p;
setMark(cur);
}
} else { // off < 0: retreat
cur.tag += off; // restore tag
if (prev == null) return;
p = cur; cur = prev; off = memory[cur.tag]; padr = cur + off;
prev = memory[padr]; memory[padr] = p;
}
}
}

This is the GC of Oberon


4 bytes overhead per object
any number of pointers per object
pointers may be at arbitrary
positions
fixed memory requirements

24

Sweep phase
Heap after the mark phase
free list

allocated and marked


allocated but unmarked
free

Tasks of the sweep phase

traverses all heap blocks sequentially


merges adjacent free blocks
builds a new free list
clears the mark bits

Heap after the sweep phase


free list

25

Sweep algorithm

void sweep() {
Pointer p = heapStart + 4;
Pointer free = null;
while (p < heapEnd) {
if (p.marked) p.marked = false;
else { // free: collect p
int size = p.tag.size;
Pointer q = p + size;
while (q < heapEnd && !q.marked) {
size += q.tag.size; // merge
q = q + q.tag.size;
}
p.tag = p; p.tag.size = size;
p.tag.next = free; free = p;
}
p += p.tag.size;
}
}

allocated block
p

tag

size
size

free block
p

tag
size
next

When p.tag is accessed the free bit must


be masked to be 0 in free blocks

26

Lazy sweep
Problems
Sweep must visit every block (takes some time if the heap is hundreds of megabytes large)
In virtual memory systems any swapped pages must be swapped in and later swapped out again

Lazy sweep Sweep is done incrementally on demand


after mark()

scan
p = alloc(size);

free

marked
unmarked
free

no block in free list partial sweep

free

scan

until a sufficiently large block is freed and alloc() can proceed

free

scan
27

Lazy sweep (continued)


free
p = alloc(size);

scan

no sufficiently large block in free list partial sweep

free

scan

free

scan

alloc() can proceed

Requirements
Mark bits remain set while the program (the mutator) runs
(they must be masked out when the type tag is accessed)
mark() must only be restarted after the whole sweep has ended
28

2. Garbage Collection
2.1 Motivation
2.2 Basic techniques
2.2.1 Reference Counting
2.2.2 Mark & Sweep
2.2.3 Stop & Copy

2.3

Variants
2.3.1 Mark & Compact
2.3.2 Generation scavenging

2.4

Incremental garbage collection


2.4.1 Tricolor marking
2.4.2 Train algorithm

2.5

Root pointers
2.5.1 Pointer tables
2.5.2 Conservative garbage collection

2.6 Garbage collection in multi-threaded systems


2.7 Finalization
2.8 Case study: Java Hotspot VM
2.9 Case study: .NET
29

Stop & Copy


The heap is divided into two parts: fromSpace and toSpace
New objects are allocated in fromSpace

top

toSpace

fromSpace
Simple sequential alloc(size)
top = top + size;

If fromSpace is full all live objects are copied to toSpace (scavenging)


root pointers
a

g
top

fromSpace

toSpace
30

Scavenging (phase 1)
a

1. Copy all objects that are directly referenced by roots

b
scan

fromSpace

d
top

toSpace

Change root pointers to point to the copied objects


Mark copied objects in fromSpace so that they are not copied again
Install a forwarding pointer to the copy in toSpace
Set a scan pointer to the start of toSpace
Set a top pointer to the end of toSpace

31

Scavenging (phase 2)
2. Move the scan pointer through the objects in toSpace
a

scan

top

if scan hits a pointer:


- copy the referenced object to toSpace (if not already copied)
mark the copied object in fromSpace and install a forwarding pointer to the copy
- change the pointer to point to the copy
a

d
top

scan

f
top

scan
a

ready if
scan == top

f
top
scan

32

Scavenging (phase 3)
3. Swap fromSpace and toSpace
b

f
top

toSpace

fromSpace

New objects are allocated sequentially in fromSpace again

Advantages

Disadvantages

single-pass algorithm
no mark()
purely sequential; no graph traversal
heap is compacted
(no fragmentation, better locality)
simple alloc()
run time independent of heap size;
depends only on the number of live objects

only half of the heap can be used


for allocation
copying costs time
objects change their address
=> pointers have to be adjusted

33

Comparison of the 3 basic techniques


Run time performance
Reference Counting
Mark & Sweep

time number of pointer assignments + number of dead objects


time number of live objects + heap size

Stop & Copy

time number of live objects

Overheads

for pointer assignments


for copying
for alloc()
for heap traversal

RC
***

M&S

S&C
***

*
***

GC and virtual memory


Sweep swaps all pages in (others are swapped out)
S&C can use big semi-spaces, because toSpace is originally on the disk anyway.
While toSpace gets full its pages are swapped in and fromSpace gets swapped out

34

2. Garbage Collection
2.1 Motivation
2.2 Basic techniques
2.2.1 Reference Counting
2.2.2 Mark & Sweep
2.2.3 Stop & Copy

2.3

Variants
2.3.1 Mark & Compact
2.3.2 Generation scavenging

2.4

Incremental garbage collection


2.4.1 Tricolor marking
2.4.2 Train algorithm

2.5

Root pointers
2.5.1 Pointer tables
2.5.2 Conservative garbage collection

2.6 Garbage collection in multi-threaded systems


2.7 Finalization
2.8 Case study: Java Hotspot VM
2.9 Case study: .NET
35

Mark & Compact


Compacting variant of Mark & Sweep
Mark all reachable blocks

Sweep 1: For every marked block compute its address after compaction
0

16

32

Sweep 2: Adjust roots and pointer fields to point to the new addresses
Sweep 3: Move blocks to the computed addresses

16

32

Advantages

Disadvantages

+
+
+
+

- objects must be copied (moved)


- needs an additional address field per block
- 3 sweeps necessary => slow

removes fragmentation
simple sequential alloc()
order of objects on the heap is retained
good locality (virtual memory, caches)

36

2. Garbage Collection
2.1 Motivation
2.2 Basic techniques
2.2.1 Reference Counting
2.2.2 Mark & Sweep
2.2.3 Stop & Copy

2.3

Variants
2.3.1 Mark & Compact
2.3.2 Generation scavenging

2.4

Incremental garbage collection


2.4.1 Tricolor marking
2.4.2 Train algorithm

2.5

Root pointers
2.5.1 Pointer tables
2.5.2 Conservative garbage collection

2.6 Garbage collection in multi-threaded systems


2.7 Finalization
2.8 Case study: Java Hotspot VM
2.9 Case study: .NET
37

Generation scavenging -- idea


Variant of Stop&Copy

Problems 1) Long-living objects must be copied in every GC run.


2) Most objects die young!

Solution

Distinguish between short-living and long-living objects

newFrom

top1

Young generation
(short-living objects)
newTo
Old generation
(long-living objects)

top2

oldFrom

oldTo

New objects are always allocated in newFrom


GC for newFrom is performed more frequently than for oldFrom;
objects that have been copied n times get "tenured" (are copied to oldFrom)
Good for languages with many short-living objects (e.g. Smalltalk)
- only 5% of the objects survive the first collection
- only 1% of the objects survive the second collection (but those live very long)
newFrom often small (< 128 KB); managed with Stop&Copy
oldFrom often large; managed with Mark&Compact or with an incremental GC

38

Cross-generation pointers
Pointers from newFrom to oldFrom
newFrom

newTo

oldFrom

oldTo

Before every old-GC a new-GC is performed


Pointer from new to old are detected and
considered as roots for old-GC

Pointers from oldFrom to newFrom


newFrom

newTo

oldFrom

oldTo

remembered set

If an object is copied from newFrom to oldFrom,


any pointers from old to new are stored in a
so-called "remembered set"
The remembered set is used as a root table
for new-GC
There is empirical evidence that there are more
pointers from newFrom to oldFrom than vice versa

39

Write barriers
Problem: pointer assignments
new

new
newFrom

old

newFrom

old.f = new;

oldFrom

old

oldFrom

Installs a pointer from oldFrom to newFrom.


How does the GC notice that?

Compiler must generate "write barriers"


At every pointer assignment
old.f = new;

the following code must be generated:


if (old in oldFrom && new in newFrom)
add Addr(old.f) to rememberedSet;

Check can be implemented efficiently


(see later)
Such pointer assignments are rare
Costs about 1% of run time in Java
Optimizations possible, e.g.:
assignments to this.f in a constructor cannot
install a pointer from oldFrom to newFrom
40

Tenured garbage
Dead objects in the old generation
newFrom

oldFrom

Tenured garbage may keep dead objects in the young generation alive
=> should be avoided if possible

Tenuring threshold
n: Number of copy runs until an object is copied to oldFrom
Dilemma
n small => much tenured garbage
n large => long-living objects remain in young generation longer than necessary
=> long GC times
41

Adaptive tenuring (Ungar 1988)


Keep tenuring threshold flexible (depending on the amount of live objects in newFrom)
Object age
Every object remembers how often it was copied in the young generation (age field)

Age table
How many bytes of every age are in newFrom?
age

bytes

1
2
3

50000
9000
8000

i.e. 8000 bytes were already copied 3 times

Watermark
Assume that the tolerated maximum GC pause is 1 ms
=> watermark = max. number of bytes, which can be copied in this time

42

Adaptive Tenuring (continued)


Situation after copying
survived objects < watermark
toSpace

=> tenureAge =

watermark

i.e. during the next GC run no objects are


copied to oldSpace

survived objects > watermark

=> tenureAge must be chosen such that at least d bytes are tenured
in the next GC run
1
2
3

50000
9000
8000

e.g. d = 10000 => all objects with age >= 2 are


copied to oldFrom in the next GC run.

43

2. Garbage Collection
2.1 Motivation
2.2 Basic techniques
2.2.1 Reference Counting
2.2.2 Mark & Sweep
2.2.3 Stop & Copy

2.3

Variants
2.3.1 Mark & Compact
2.3.2 Generation scavenging

2.4

Incremental garbage collection


2.4.1 Tricolor marking
2.4.2 Train algorithm

2.5

Root pointers
2.5.1 Pointer tables
2.5.2 Conservative garbage collection

2.6 Garbage collection in multi-threaded systems


2.7 Finalization
2.8 Case study: Java Hotspot VM
2.9 Case study: .NET
44

Motivation
Goal
Avoid long GC pauses (pauses should be less than 1 ms)

Application areas
For soft real-time systems (hard real-time systems should not use a GC at all)
For the old generation in a generational GC
GC pause is longer for the old generation because:
- old generation is larger than young generation
- there are more live objects in the old generation than in the young generation

Idea
GC (collector) and application program (mutator) run in parallel (interleaved)
a) collector runs continuously as a background thread
b) collector stops the mutator, but does only a partial collection

Problem
Mutator interferes with the collector!
Can change data structures, while the collector is visiting them
45

Suitability of basic techniques for incr. GC


Reference Counting

yes

Counter updates do not cause substantial pauses


if counter == 0
- object reference is written to a worklist
- worklist is processed as a background thread
(reclaiming objects and writing new references to the worklist)

Mark & Sweep

no

Mutator may interfere with the mark phase


Sweep phase can run in the background,
if the mutator ignores the mark bits

Stop & Copy

a
b

a.f = d;
c

no

b is kept alive
d is collected!

Mutator may interfere


M&S and S&C must be modified in order to be able to run incrementally

46

2. Garbage Collection
2.1 Motivation
2.2 Basic techniques
2.2.1 Reference Counting
2.2.2 Mark & Sweep
2.2.3 Stop & Copy

2.3

Variants
2.3.1 Mark & Compact
2.3.2 Generation scavenging

2.4

Incremental garbage collection


2.4.1 Tricolor marking
2.4.2 Train algorithm

2.5

Root pointers
2.5.1 Pointer tables
2.5.2 Conservative garbage collection

2.6 Garbage collection in multi-threaded systems


2.7 Finalization
2.8 Case study: Java Hotspot VM
2.9 Case study: .NET
47

Tricolor marking
Abstraction of an incremental GC, from which various concrete algorithms can be derived

Idea: all objects have one of the following colors


white
black
grey

yet unseen objects (potentially garbage)


reachable and already processed objects
objects that have been seen but not yet processed
(pointers to them must still be followed)

For example in Stop&Copy


fromSpace

toSpace

scan

top

Invariant
There must never be a pointer from a black object to a white object
48

What problem can arise?


Example
a

Collector starts running


a

Problem source

Mutator interferes

A pointer to a white object is installed


into a black object

a.next = c;
b.next = null;

Collector continues
a

c is erroneously considered as garbage


b is erroneously kept alive
49

Problem solution
We have to avoid that a black object points to a white object
a

a.next = c;
b.next = null;

This can be avoided in 2 ways


Read barrier
The mutator must not see white objects.
Whenever it reads a white object, this object
is "greyed" (i.e. marked for processing)
a.next = c;

Write barrier
If a white object is installed into a black object
the black object is "greyed"
(i.e. it must be revisited)
a.next = c;

Read barriers are more conservative,


because the white object that is read
need not be installed in a black object
Read barriers are expensive if implemented in software.
There are more pointer reads than
pointer writes
Read barriers usually for Stop&Copy
Write barrier usually for Mark&Sweep

In both cases b is left over as "floating


garbage"; but it is reclaimed in the
next GC run.
50

Baker's algorithm (read barrier)


a

1. Copy all objects that are directly referenced by roots


a

d'

scan top

2. New objects are allocated at the end of toSpace


they are conceptually black (they do not contain pointers to white objects)
a

d'

scan top

new

3. At every alloc() do also an incremental scan/copy step


a

b'

d'

scan top

new

51

Baker's algorithm (continued)


a

b'

d'

scan top

new

4. If the mutator accesses a white object, this object is copied and becomes grey
(read barrier)
e.g. after accessing a
a'

b'

d'

scan

top new

Read barrier: a = get(a);


Mutator sees only toSpace objects

Pointer get (Pointer p) {


if (p points to fromSpace) {
if (p not already copied)
copy p to top;
p.forward = top;
top = top + p.size;
}
p = p.forward;
}
return p;
}

Can also be implemented with virtual memory:


fromSpace is protected so that every read access causes a trap

Problems
- Requires a read barrier for every read access to a white object (20% of the run time)
- Can only be implemented efficiently with special hardware or OS support (virtual memory)
52

Write barrier algorithms


Catch pointer writes, not pointer reads
+ Writes are less frequent than reads (5% vs. 15% of all instructions) => more efficient
- Works only for Mark&Sweep, not for Stop&Copy:
Stop&Copy requires read barriers, because if an object that has already been copied
is accessed again in fromSpace the access must be redirected to the copy in toSpace

Problematic case
p

p.f = q;
q = ...;

Two conditions must hold in order to cause a problem:


a) a white object is installed in a black object (p.f = q;)
b) all other pointers to the white object disappear (q = ...;)
At least one of these conditions must be prevented

2 kinds of write barrier algorithms


Snapshot at beginning (prevents condition b)
Incremental update (prevents condition a)
53

Snapshot at beginning
Objects stay alive, if they were reachable at the beginning of the GC run
p

p.f = q;

obj

q
obj was reachable and thus
must stay alive
obj

If a pointer is removed from an object


the object is greyed

Prevents that the last pointer to an object disappears (condition b)


p
q
p
q
a) p.f = q;
b) q = ...;

Implementation:
ptr = ...;

worklist.add(ptr);
ptr = ...;

Write barrier generated by the compiler;


worklist is processed by the GC later

Catches all pointer assignments (not only assignments to pointers in black objects)
Very conservative!

54

Incremental update
Objects stay alive, if they are reachable at the end of the GC run
p

a) p.f = q;

q
obj

obj

if q disappears,
obj is visited nevertheless
if a pointer to a white object is
installed in a black object
the white object is greyed

Prevents that white objects are installed in black ones (condition a)


Implementation:
Write barrier generated by the compiler;
p.f = q;
if (black(p) && white(q))
worklist is processed by the GC later
worklist.add(q);
p.f = q;

Catches only assignments to pointers in black objects


(more accurate than "snapshot at beginning")

55

2. Garbage Collection
2.1 Motivation
2.2 Basic techniques
2.2.1 Reference Counting
2.2.2 Mark & Sweep
2.2.3 Stop & Copy

2.3

Variants
2.3.1 Mark & Compact
2.3.2 Generation scavenging

2.4

Incremental garbage collection


2.4.1 Tricolor marking
2.4.2 Train algorithm

2.5

Root pointers
2.5.1 Pointer tables
2.5.2 Conservative garbage collection

2.6 Garbage collection in multi-threaded systems


2.7 Finalization
2.8 Case study: Java Hotspot VM
2.9 Case study: .NET
56

Idea
Incremental Stop&Copy algorithm with write barriers (primarily for old generation)

The heap is divided into segments ("cars") of fixed size (e.g. 64 KBytes)
"car"

"car"

"car"
"train"
Every car has a remembered set:
addresses of pointers from later cars
to this car (= additional roots)

Every GC step collects exactly 1 car (the first one)


- copies live objects to other cars
- releases the first car
GC of a single car is fast => no noticeable overhead

Objects that are larger than 1 car are managed in a separate heap
(large object area)
57

Dealing with dead cycles


Problem
Dead cycle across several cars
x

If the first car is collected we don't see


that x is dead, because it is referenced from
a later car.

Simple solution
All objects of a dead cycle must be copied into the same car

...

If this car is collected the whole cycle is


released together with the car

Does not always work ...


... because the objects of a cycle
may not fit into a single car
=> This is where the train algorithm comes in
58

Train algorithm
Cars are grouped into several trains
1.1

1.2

1.3

train 1
2.1

2.2

train 2
3.1

3.2

3.3

3.4

train 3
Order of processing: 1.1 < 1.2 < 1.3 < 2.1 < ... < 3.3 < 3.4

Our goal is to accumulate dead cycles in the first train


train 1

Objects that are referenced by roots or from


other trains are evacuated to later trains

train 2
If no object in the first train is referenced from outside the first train
=> release the whole first train!

59

Remembered sets
Remembered set of a car x
Contains addresses of pointers from later cars to x
a

c
b

c d

Additionally, there is a list of roots pointing from outside the heap


into the cars

60

Updating remembered sets


Write barriers

p
f

p.f = q;
p.f
Remembered Set

If car(q) is before car(p) (i.e. if this is a pointer from back to front)


=> add address of p.f to remembered set of car(q)

61

Car ordering
Cars are logically ordered!
Their physical addresses need not be in ascending order (cars may be anywhere in the heap)
train 1 1.1

1.2

40000 10000

train 2 2.1

1.3
20000

physical addresses
(hexadecimal)

2.2

50000 00000

train 3 3.1

3.2

70000 90000

3.3

3.4

30000

80000

Car table
maps physical address to car number
e.g. car size 2k (e.g. 216 bytes = 64 KBytes)
car index n = (adr - heapStart) >> k;
tab[n] tells us which car is stored at adr

n
0 0000
1 0000
2 0000
3 0000
4 0000
5 0000
6 0000
7 0000
8 0000
9 0000
10 0000

tab
2.2
1.2
1.3
3.3
1.1
2.1
3.1
3.4
3.2
...

Example
pointer from 30AF4 to 50082
from tab[3] to tab[5]
from 3.3 to 2.1
from back to front

62

Incremental GCstep
r

a (from the same train)

b (from some other train)


a b

if (there are no pointers to the first train from outside this train)
release the whole first train;
else {
car = first car of first train;
copy
for (all p in rememberedSet(car)) {
copy pobj to the last car of train(p);
if full, start a new car in train(p);
}
for (all roots p that point to car) {
copy pobj to the last car of the last train (not to the first train!);
if full, start a new train;
}
scan
for (all p in copied objects)
if (p points to car) {
copy pobj to last car of train(p);
if full, start a new car in train(p);
} else if (p points to a car m in front of car(p))
add p to rememberedSet(m);
release car;
}

Additional considerations
How to find pointers from outside
this train: inspect roots and
remembered sets of all cars
of this train.
If there are multiple pointers to
the same object => don't copy
this object twice, but install a
forwarding pointer.
Cars and trains must be linked
in order to find the first and the
last car of a train.

63

Example
B, F

root
R

Assumption: our cars have only


space for 3 objects

copy R to the last car of the last train (because it is referenced from a root)
copy A to the last car of train(B)
copy C to the last car of train(F)

B
root

A
64

Example (continued)
R, C

B
root

copy S to the last car of train(R); no space => start a new car in train(R)
copy D to the last car of train(C); no space => start a new car in train(C)
copy E to the last car of train(D)
T
F

B
root

A
S

65

Example (continued)
S, E

T
F

B
root

copy T to the last car of train(S)


copy F to the last car of train(E)
copy C to the last car of train(F); no space => start a new car
F
D

B
root

A
S

66

Example (continued)
C

F
D

B
root

A
S

no pointers to the first train from ouside this train => release the whole first train

67

Example (continued)
B
root

copy R to the last car of the last train;


Since there is only one train, start a new train
B

A
S

root

68

Example (continued)
B

A
S

root

no references into the first car => release first car

69

Example (continued)
R

root

copy S (and also T) to the last car of train(R)

T
root

ready!
Only live objects survived
In every step at least 1 car was released => progress is guaranteed
70

2. Garbage Collection
2.1 Motivation
2.2 Basic techniques
2.2.1 Reference Counting
2.2.2 Mark & Sweep
2.2.3 Stop & Copy

2.3

Variants
2.3.1 Mark & Compact
2.3.2 Generation scavenging

2.4

Incremental garbage collection


2.4.1 Tricolor marking
2.4.2 Train algorithm

2.5

Root pointers
2.5.1 Pointer tables
2.5.2 Conservative garbage collection

2.6 Garbage collection in multi-threaded systems


2.7 Finalization
2.8 Case study: Java Hotspot VM
2.9 Case study: .NET
71

Root pointers
Roots are all live pointers outside the heap
local variables on the stack
reference parameters on the stack (can point to the middle of an object!)
global variables in C, C++, Pascal, ...
(static variables in Java are on the heap (in class objects))
registers
stack

registers

global variables

heap

All objects that are (directly or indirectly) referenced from roots are live
Mark & Sweep:
for (all roots p) mark(p);
sweep();

Stop & Copy:


for (all roots p) copy referenced object to toSpace;
scan();

72

2. Garbage Collection
2.1 Motivation
2.2 Basic techniques
2.2.1 Reference Counting
2.2.2 Mark & Sweep
2.2.3 Stop & Copy

2.3

Variants
2.3.1 Mark & Compact
2.3.2 Generation scavenging

2.4

Incremental garbage collection


2.4.1 Tricolor marking
2.4.2 Train algorithm

2.5

Root pointers
2.5.1 Pointer tables
2.5.2 Conservative garbage collection

2.6 Garbage collection in multi-threaded systems


2.7 Finalization
2.8 Case study: Java Hotspot VM
2.9 Case study: .NET
73

Global pointers
Global pointer variables in Oberon
For every module the compiler writes a list of global pointer addresses to the object file
The loader creates a pointer offset table for every loaded module

module A

module B

module C

list of loaded modules


global pointer tables

for (all loaded modules m)


for (all pointers p in m.ptrTab)
if (p != null && *p not marked) mark(p);

Static pointer variables in Java


Fields of class objects (offsets stored in type descriptors)
Loader creates class objects and stores their addresses in the roots table

74

Local pointers
For every method the compiler generates a table with pointer offsets
void foo(Obj a, int b) {
int c;
Obj d;
...
}

fromPC toPC pointer offsets registers with pointers

// a ... Offset 0
// d ... Offset 3

foo()
bar()
baz()

1000

1250

Compiler writes these tables to the object file


Loader loads them into the VM

Stack traversal in order to find local pointers


for (all stack frames f) {
meth = method containing pc of f;
for (all p in meth.ptrTab) mark(p);
for (all r in meth.regTab) mark(r);
}

75

Blocks with different pointer offsets


Blocks of the same method can have different pointer offsets (in Java)
pc1

if (...) {
int a;
Obj b;
...
} else {
Obj c;
int d;
}

0
1

a
b

0
1

c
d

pc2
pc3

pc4

Pointer offset table must have several regions per method


from

to

pointer offsets

pc1

pc2

pc3

pc4

In the Hotspot VM this is solved via safepoints (see later)


Also allows that a register may contain a pointer or a non-pointer at different locations

76

Pointers in objects
class Person {
int id;
String name;
String address;
int zip;
}

Type descriptors contain pointer offsets


p

0
1
2
3

tag
id
name
address
zip

type descriptor
1
2

pointer offsets

Compiler writes type descriptor to the object file


Loader loads type descriptor when the corresponding class is loaded
new Person() installs the type descriptor in the Person object

77

2. Garbage Collection
2.1 Motivation
2.2 Basic techniques
2.2.1 Reference Counting
2.2.2 Mark & Sweep
2.2.3 Stop & Copy

2.3

Variants
2.3.1 Mark & Compact
2.3.2 Generation scavenging

2.4

Incremental garbage collection


2.4.1 Tricolor marking
2.4.2 Train algorithm

2.5

Root pointers
2.5.1 Pointer tables
2.5.2 Conservative garbage collection

2.6 Garbage collection in multi-threaded systems


2.7 Finalization
2.8 Case study: Java Hotspot VM
2.9 Case study: .NET
78

Conservative garbage collection


Used if the compiler does not generate pointer tables (e.g. in C/C++)

"Guess" which memory locations contain pointers


Check every word w (on the stack, in the global data area, in heap objects, in registers)
w is a possible pointer if
- w points to the heap (easy to check)
- w points to the beginning of an object (difficult to check)

Guessing must be done conservatively


If the guess is wrong (w is actually an int and not a pointer), no harm must occur
What if the guess was wrong?
Mark&Sweep: an object is marked although it may be garbage
=> no harm
Stop&Copy: the "wrong pointer" (which is actually an int) is changed to the new object location
=> destroys data
Ref. Counting: only for searching pointers in deallocated objects;
Counter is decremented, although the object was not referenced by w
=> counters become inconsistent
79

Implementation with a candidate list


All possible pointers are collected in a list
for (all words w in stack, global data and registers) {
if (heapStart <= w < heapEnd) candidates.add(w);
}
candidates.sort();
i = 0; p = heapStart;
while (i < candidates.size() && p < heapEnd) {
if (candidates[i] == p) {
if (!p.marked) mark(p);
i++; p = p + p.size;
} else if (candidates[i] < p) {
i++;
} else { // candidates[i] > p
p = p + p.size;
}
}

candidates
i

heap

Requires a full heap traversal to find the pointers


In principle, mark() must inspect all words of an object in a similar way
Sometimes a mixture: pointer tables for objects, conservative GC for stack etc. (e.g. in Oberon)

80

Implementation with an allocation bitmap


Blocks are allocated in multiples of 32 bytes (32, 64, 96, ...)
There is a bitmap with 1 bit per 32 byte of heap area
An address a is the beginning of a block bit[a >> 5] == 1
heapStart

Heap
0

32

64

96

128

allocation bitmap
bit
b
= b - (heapStart >> 5)

Bitmap requires 1 bit per 32 bytes (256 bits) => 1/256 = 0.4% of the heap
alloc() must set the bits
sweep() must reset the bits
for (all words w in stack, global data and registers) {
if (heapStart <= w < heapEnd && bit[w >> 5] && !w.marked) mark(w);
}

+
+
-

does not need a candidate list


does not need an additional heap traversal
overhead for maintaining the bitmap
bit operations are expensive

81

2. Garbage Collection
2.1 Motivation
2.2 Basic techniques
2.2.1 Reference Counting
2.2.2 Mark & Sweep
2.2.3 Stop & Copy

2.3

Variants
2.3.1 Mark & Compact
2.3.2 Generation scavenging

2.4

Incremental garbage collection


2.4.1 Tricolor marking
2.4.2 Train algorithm

2.5

Root pointers
2.5.1 Pointer tables
2.5.2 Conservative garbage collection

2.6 Garbage collection in multi-threaded systems


2.7 Finalization
2.8 Case study: Java Hotspot VM
2.9 Case study: .NET
82

GC in multi-threaded systems
Problems
Several mutator threads -- all must be stopped before GC runs
GC is not allowed at all locations, e.g.
MOV EAX, objAdr
ADD EAX, fieldOffset
MOV [EAX], value

GC is not allowed here, because the object


may be moved

Safepoints (GC points)


Locations where GC is allowed
Threads can only be stopped at safepoints
For every safepoint there is
- a table of pointer offsets in the current stack frame
- a list of registers containing pointers

Stopping threads at safepoints can be implemented in 2 ways


Safepoint polling
Safepoint patching
83

Safepoint polling
Mutator checks at safepoints if GC is pending

Safepoints

method entry (enter)


method exit (return)
system calls
backward jumps

guarantees that every thread reaches the next


safepoint quickly

Compiler emits the following code at every safepoint


if (gcPending) suspend();

or:

MOV dummyAdr, 0

If gcPending, the memory


page dummyAdr is made
readonly
=> Trap => suspend()

If the system runs out of memory ...


gcPending = true;
suspend all threads;
for (each thread t)
if (not at a safepoint) t.resume(); // let it run to the next safepoint
// all threads are at safepoints
collect();
gcPending = false;
resume all threads;

Thread1
...
PC ...
...
...
...
...

Thread2
...
...
...
...
Safe...
point
...
84

Safepoint patching
Safepoints are patched with instructions that cause a thread to be suspended

Safepoints
method call
method exit (return)
backward jump

because of dynamic binding the invoked method is unknown


=> would require too many methods to be patched

If the system runs out of memory ...


suspend all threads;
for (each thread t) {
patch next safepoint with a trap instruction;
t.resume(); // let it run until the next safepoint
}
// all threads are at safepoints
collect();
restore all patched instructions;
resume all threads;

PC at the time when the


system runs out of memory

call trap

call trap

85

2. Garbage Collection
2.1 Motivation
2.2 Basic techniques
2.2.1 Reference Counting
2.2.2 Mark & Sweep
2.2.3 Stop & Copy

2.3

Variants
2.3.1 Mark & Compact
2.3.2 Generation scavenging

2.4

Incremental garbage collection


2.4.1 Tricolor marking
2.4.2 Train algorithm

2.5

Root pointers
2.5.1 Pointer tables
2.5.2 Conservative garbage collection

2.6 Garbage collection in multi-threaded systems


2.7 Finalization
2.8 Case study: Java Hotspot VM
2.9 Case study: .NET
86

Goal
Cleanup work to be done before an object is reclaimed
closing open files
terminating threads
e.g. in Java
class T {
...
protected void finalize() throws Throwable {
... // cleanup work
super.finalize();
}
}

is automatically called before a T object is reclaimed


avoid finalizers if possible
reclamation of finalized object is delayed (see later)

87

Finalization during GC (e.g. in Oberon)


Objects with a finalize() method are entered into a finalization list when they are allocated
=> new() takes a little longer
Finalization list entries must not be considered as pointers,
otherwise these objects would never be garbage collected

Finalization during Mark&Sweep


mark();
for all unmarked objects in the finalization list:
- obj.finalize();
- remove obj from finalization list
sweep();

Finalization during Stop&Copy


scan();
for all objects in the finalization list, which have not been copied
- obj.finalize();
- remove obj from finalization list
=> increases the GC pause!
88

Finalization in the background


(e.g. in Java and .NET)
mark();
for all unmarked objects obj in the finalization list
- worklist.add(obj);
- set mark bit of obj
sweep();
background thread processes worklist
- calls obj.finalize();
- clears mark bit
- remove obj from finalization list
object is collected during the next GC run

Finalization can happen at any time after GC!


No guarantee that finalization will happen at all
until the end of the program

=> no substantial increase of GC pauses


but objects that have to be finalized are released with a delay
Object resurrection
protected void finalize() throws Throwable {
...
globalVar = this;
}

brings finalized object to life again!

next GC will detect this object as live => keep it


if object finally dies => no finalizer call again!
89

2. Garbage Collection
2.1 Motivation
2.2 Basic techniques
2.2.1 Reference Counting
2.2.2 Mark & Sweep
2.2.3 Stop & Copy

2.3

Variants
2.3.1 Mark & Compact
2.3.2 Generation scavenging

2.4

Incremental garbage collection


2.4.1 Tricolor marking
2.4.2 Train algorithm

2.5

Root pointers
2.5.1 Pointer tables
2.5.2 Conservative garbage collection

2.6 Garbage collection in multi-threaded systems


2.7 Finalization
2.8 Case study: Java Hotspot VM
2.9 Case study: .NET
90

Heap layout
Two generations
young generation

fromSpace

nursery

toSpace

Stop&Copy
New objects are allocated in the nursery
if full => copy fromSpace + nursery to toSpace
advantage: less waste for toSpace
if overflow => copy remaining objects to old
after n copy passes an object is copied to old
n is variable (adaptive tenuring)
many new objects => faster "tenuring"

old generation
Mark&Compact
is executed less frequently

Remembered set
List of all pointers from old to young
An entry is made
- if an object with pointers to other young objects is tenured
- if a pointer to young is installed in an old object (detected by a write barrier)
91

Write barriers
Card-marking scheme
heapStart

heap

divided into
"cards" of 512 bytes

dirty
= a - (heapStart >> 9)

dirty table: 1 byte(!) per card (byte ops are faster than bit ops)
1 ... card unmodified
0 ... card modified

If a pointer is installed into an object: obj.f = ...; (no matter where it points to):
LEA
MOV
SHR
MOV
ADD
MOV

EAX, obj
EBX, EAX
EBX, 9
byte ptr dirty[EBX], 0
EAX, offset(f)
[EAX], ...

3 instructions per pointer write


generated by the compiler (only for field assignments, not for assignments to pointer variables)
write barriers cost about 1% of the run time
GC searches all dirty cards in oldSpace for objects;
any pointers in them that point to newSpace are entered into rememberedSet
92

Searching for objects in cards


Objects may overlap card boundaries
d1

d2

heap consisting of cards

d1 d2

offset table
1 byte per card
how far does the first object extend into the predecessor card?
if it overlaps the whole predecessor card:
offset = 255 => search one card before
Objects are aligned to 4 byte boundaries
=> table holds offset / 4

for (all dirty cards i in oldSpace) {


obj = heapStart + 512 * i; cardEnd = obj + 512; j = i;
while (offset[j] == 255) { obj = obj - 512; j--; }
obj = obj - offset[j] * 4;
while (obj < cardEnd) {
for (all pointers p in obj.ptrTab)
if (p points to newSpace) rememberedSet.add(p);
obj += obj.size;
}
}

27

28

29

32

obj
27

27
1

cardEnd
28
8

29

28
0

29
1

offset
dirty
93

Object layout
class A {
Obj x;
int y;
Obj z;
}
class B extends A {
int a;
Obj b;
Obj c;
}

aging
4

mark, lock
26
tag
x
z
y
b
c
a

2
2
2

All pointers of a class are stored in a contiguous area


2 words overhead per object
First word is used for the new target address in Mark&Compact

94

Pointers on the stack


Stack can hold frames of compiled or interpreted methods

For interpreted methods


Analyze the bytecodes to find out where the pointers are

For compiled methods


Compiler generates a pointer table for every safepoint
(call, return, backward branch and every instruction that can throw an exception)
GC can only happen at safepoints
Safepoint polling: at every safepoint there is the instruction:
MOV dummyAdr, 0

If GC is pending, the memory page dummyAdr is made readonly => trap => suspend()

95

G1 -- Garbage-first collector
Alternative GC for server applications (large heaps, 4+ processors)
Since Java 6

Main ideas
1. Incremental GC (similar to train algo)
A

...

RSA

RSB

Heap is divided into equally sized regions (~1MB)


Remembered set per region (contain pointers from
any region to this region; in contrast to train algo)

RSC

2. Collect regions with largest amount of garbage first


...
100

250

270

Regions are logically sorted by collection costs


- number of live bytes to be copied
- size of remembered set

3. Allocate new objects in "current region" (if full, start new current region)
96

G1 -- Computing live objects


Global marking phase (started heuristically from time to time)
Mark all live objects (concurrently to the mutator)
foreach (root pointer r) mark(r);
while (!todo.empty()) {
p = todo.remove();
foreach (pointer q in *p) mark(q);
}

mark (p) {
if (*p not marked) {
mark *p;
todo.add(p);
}
}

Mark bits are kept in separate bitmap (1 bit per 8 bytes)


avoids synchronization between mutator and marker

97

G1 -- Building remembered sets


Write barriers
Mutator threads use write barriers to catch pointer updates during marking.
Snapshot at beginning: make object grey if pointer to it is removed
p

q
f

p.f = q;

has to be visited for marking

Write barriers also build (update) the remembered sets


q

p.f = q;

RS

98

young

G1 -- Generations
eden regions

those in which new objects have been allocated recently

survivor regions

contain objects with age < tenureAge

old regions

all other regions

Incremental evacuation step (while all mutator threads are stopped)


Evacuate young regions to survivor regions or old regions
eden

eden

survivor survivor

old

old

old

...

Adapt number of young regions such that evacuation does not exceed tolerated pause time
If time permits, evacuate also old regions with largest amount of garbage
young

survivor survivor

old

old

old

old

...

tolerated GC pause time

For evacuation of region R use rootsR and RSR


After evacuation update remembered sets
For details see: David Detlefs et al.: Garbage-First Garbage Collection.
In Proc. Intl. Symp. on Memory Management (ISMM'04), Vancouver, Oct 24-25, 2004

99

2. Garbage Collection
2.1 Motivation
2.2 Basic techniques
2.2.1 Reference Counting
2.2.2 Mark & Sweep
2.2.3 Stop & Copy

2.3

Variants
2.3.1 Mark & Compact
2.3.2 Generation scavenging

2.4

Incremental garbage collection


2.4.1 Tricolor marking
2.4.2 Train algorithm

2.5

Root pointers
2.5.1 Pointer tables
2.5.2 Conservative garbage collection

2.6 Garbage collection in multi-threaded systems


2.7 Finalization
2.8 Case study: Java Hotspot VM
2.9 Case study: .NET
100

GC in .NET
Mark & Compact with multiple generations
1. Objects are allocated sequentially (no free list)

top

2. If the heap is full => mark()


A

3. compact()
New objects are allocated sequentially again
A

generation 1

D
generation 0

top

4. If the heap is full => mark&compact only for generation 0!


faster; most dead objects are in generation 0

generation 2

generation 1

generation 0

top

101

GC in .NET
generation 2

generation 1

generation 0

top

Currently restricted to 3 generations


From time to time there is a GC of generations 0+1 or generations 0+1+2 (heuristic)
Pointers from generation 1+2 to generation 0 are detected with write barriers
- GetWriteWatch(..., oldGenArea, dirtyPages) returns all dirty pages in oldGenArea
- these must be searched for pointers to generation 0
Objects larger than 20 KBytes are kept in a special heap (Mark&Sweep without compaction)
GC of generation 0 takes less than 1 ms
Threads are stopped at safepoints before the GC runs

102

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy