Transcript Slides

Lecture 17:
Garbage
Collection
CS201j: Engineering Software
University of Virginia
Computer Science
David Evans
http://www.cs.virginia.edu/evans
Menu
•
•
•
•
•
Stack and Heap
Mark and Sweep
Stop and Copy
Reference Counting
Java’s Garbage Collector
5 November 2002
CS 201J Fall 2002
2
Stack and Heap Review
Heap
Stack
public class Strings {
public static void test () {
A
StringBuffer sb = new StringBuffer
("hello");
B }
static public void main (String args[]) {
1
test ();
2
test ();
3
}
}
sb
java.lang.StringBuffer
“hello”
When do the stack and heap look like this?
5 November 2002
CS 201J Fall 2002
3
Stack and Heap Review
Stack
Heap
public class Strings {
public static void test () {
StringBuffer sb = new StringBuffer
("hello");
B }
static public void main (String args[]) {
test ();
2
test ();
}
}
5 November 2002
sb
CS 201J Fall 2002
java.lang.StringBuffer
“hello”
4
Garbage Heap
Stack
Heap
public class Strings {
public static void test () {
StringBuffer sb = new StringBuffer
("hello");
}
}
static public void main (String args[]) {
while (true) test ();
}
“hello”
“hello” “hello”
“hello”
“hello”
“hello”
“hello”“hello” “hello”
“hello”
“hello”
“hello”
“hello” “hello”
“hello”
“hello”
“hello” “hello”
“hello”
“hello”
“hello” “hello”
“hello”
“hello”
“hello” “hello”
“hello”
“hello”
5 November 2002
CS 201J Fall 2002
5
Garbage Collection
• System needs to reclaim storage on the
heap used by garbage objects
• How can it identify garbage objects?
• How come we don’t need to garbage
collect the stack?
5 November 2002
CS 201J Fall 2002
6
Mark and Sweep
5 November 2002
CS 201J Fall 2002
7
Mark and Sweep
• John McCarthy, 1960 (first LISP
implementation)
• Start with a set of root references
• Mark every object you can reach from
those references
• Sweep up the unmarked objects
What are the root references?
References on the stack.
5 November 2002
CS 201J Fall 2002
8
public class Phylogeny {
static public void main (String args[]) {
SpeciesSet ss = new SpeciesSet ();
… (open file for reading)
while (…not end of file…) {
Species current = new Species (…name from file…,
…genome from file…);
ss.insert (current);
}
}
public class SpeciesSet {
private Vector els;
public void insert (/*@non_null@*/ Species s) {
if (getIndex (s) < 0) els.add (s); }
5 November 2002
CS 201J Fall 2002
9
“in.spc”
Stack
name:
genome:
Bottom of Stack
Phylogeny.main
String[]: args
root: Species
“Duck”
els:
“CATAG”
ss: SpeciesSet
SpeciesSet.insert
current: Species
name:
genome:
this: SpeciesSet
“Goat”
s: Species
Top of Stack
“CAGTG”
name:
genome:
public class Phylogeny {
static public void main (String args[]) {
SpeciesSet ss = new SpeciesSet ();
while (…not end of file…) {
Species current = new Species (…name…, …genome…);
ss.insert (current); } }
public class SpeciesSet {
private Vector els;
5 void
November
2002
public
insert (/*@non_null@*/
Species s) {
if (getIndex (s) < 0) els.add (s); }
CS 201J Fall 2002
name:
genome:
“Elf”
“Frog”
“CGGTG”
10
“CGATG”
After els.add (s)…
“in.spc”
Stack
name:
genome:
Bottom of Stack
Phylogeny.main
String[]: args
root: Species
“Duck”
els:
“CATAG”
ss: SpeciesSet
SpeciesSet.insert
current: Species
name:
genome:
this: SpeciesSet
“Goat”
s: Species
Top of Stack
“CAGTG”
name:
genome:
public class Phylogeny {
static public void main (String args[]) {
SpeciesSet ss = new SpeciesSet ();
while (…not end of file…) {
Species current = new Species (…name…, …genome…);
ss.insert (current); } }
public class SpeciesSet {
private Vector els;
5 void
November
2002
public
insert (/*@non_null@*/
Species s) {
if (getIndex (s) < 0) els.add (s); }
CS 201J Fall 2002
name:
genome:
“Elf”
“Frog”
“CGGTG”
11
“CGATG”
SpeciesSet.insert returns…
“in.spc”
Stack
name:
genome:
Bottom of Stack
Phylogeny.main
String[]: args
root: Species
“Duck”
els:
“CATAG”
ss: SpeciesSet
SpeciesSet.insert
current: Species
name:
genome:
this: SpeciesSet
“Goat”
s: Species
Top of Stack
“CAGTG”
name:
genome:
public class Phylogeny {
static public void main (String args[]) {
SpeciesSet ss = new SpeciesSet ();
while (…not end of file…) {
Species current = new Species (…name…, …genome…);
ss.insert (current); } }
public class SpeciesSet {
private Vector els;
5 void
November
2002
public
insert (/*@non_null@*/
Species s) {
if (getIndex (s) < 0) els.add (s); }
CS 201J Fall 2002
name:
genome:
“Elf”
“Frog”
“CGGTG”
12
“CGATG”
Finish while loop…
“in.spc”
Stack
name:
genome:
Bottom of Stack
Phylogeny.main
String[]: args
root: Species
“Duck”
els:
“CATAG”
ss: SpeciesSet
current: Species
Top of Stack
name:
genome:
“Goat”
“CAGTG”
name:
genome:
public class Phylogeny {
static public void main (String args[]) {
SpeciesSet ss = new SpeciesSet ();
while (…not end of file…) {
Species current = new Species (…name…, …genome…);
ss.insert (current); } }
public class SpeciesSet {
private Vector els;
5 void
November
2002
public
insert (/*@non_null@*/
Species s) {
if (getIndex (s) < 0) els.add (s); }
CS 201J Fall 2002
name:
genome:
“Elf”
“Frog”
“CGGTG”
13
“CGATG”
Garbage Collection
“in.spc”
Stack
name:
genome:
Bottom of Stack
Phylogeny.main
String[]: args
root: Species
“Duck”
els:
ss: SpeciesSet
Top of Stack
“CATAG”
name:
genome:
“Goat”
“CAGTG”
name:
genome:
public class Phylogeny {
static public void main (String args[]) {
SpeciesSet ss = new SpeciesSet ();
while (…not end of file…) {
Species current = new Species (…name…, …genome…);
ss.insert (current); } }
public class SpeciesSet {
private Vector els;
5 void
November
2002
public
insert (/*@non_null@*/
Species s) {
if (getIndex (s) < 0) els.add (s); }
CS 201J Fall 2002
name:
genome:
“Elf”
“Frog”
“CGGTG”
14
“CGATG”
Garbage Collection
“in.spc”
Stack
name:
genome:
Bottom of Stack
Phylogeny.main
String[]: args
root: Species
“Duck”
els:
ss: SpeciesSet
Top of Stack
“CATAG”
name:
genome:
“Goat”
Initialize Mark and Sweeper:
active = all objects on stack
“CAGTG”
name:
genome:
5 November 2002
CS 201J Fall 2002
name:
genome:
“Elf”
“Frog”
“CGGTG”
15
“CGATG”
Garbage Collection
“in.spc”
Stack
name:
genome:
Bottom of Stack
Phylogeny.main
String[]: args
root: Species
“Duck”
els:
ss: SpeciesSet
Top of Stack
“CATAG”
name:
genome:
active = all objects on stack
“Goat”
while (!active.isEmpty ())
newactive = { }
“CAGTG”
foreach (Object a in active)
mark a as reachable (non-garbage)
name:
foreach (Object o that a points to)
genome:
if o is not marked
newactive = newactive U { o }
active = newactive
5 November 2002
CS 201J Fall 2002
name:
genome:
“Elf”
“Frog”
“CGGTG”
16
“CGATG”
Garbage Collection
“in.spc”
Stack
name:
genome:
Bottom of Stack
Phylogeny.main
String[]: args
root: Species
“Duck”
els:
ss: SpeciesSet
Top of Stack
“CATAG”
name:
genome:
active = all objects on stack
“Goat”
while (!active.isEmpty ())
newactive = { }
“CAGTG”
foreach (Object a in active)
mark a as reachable (non-garbage)
name:
foreach (Object o that a points to)
genome:
if o is not marked
newactive = newactive U { o }
active = newactive
5 November 2002
CS 201J Fall 2002
name:
genome:
“Elf”
“Frog”
“CGGTG”
17
“CGATG”
Garbage Collection
“in.spc”
Stack
name:
genome:
Bottom of Stack
Phylogeny.main
String[]: args
root: Species
“Duck”
els:
ss: SpeciesSet
Top of Stack
“CATAG”
name:
genome:
active = all objects on stack
“Goat”
while (!active.isEmpty ())
newactive = { }
“CAGTG”
foreach (Object a in active)
mark a as reachable (non-garbage)
name:
foreach (Object o that a points to)
genome:
if o is not marked
newactive = newactive U { o }
active = newactive
5 November 2002
CS 201J Fall 2002
name:
genome:
“Elf”
“Frog”
“CGGTG”
18
“CGATG”
Garbage Collection
“in.spc”
Stack
name:
genome:
Bottom of Stack
Phylogeny.main
String[]: args
root: Species
“Duck”
els:
ss: SpeciesSet
Top of Stack
“CATAG”
name:
genome:
active = all objects on stack
“Goat”
while (!active.isEmpty ())
newactive = { }
“CAGTG”
foreach (Object a in active)
mark a as reachable (non-garbage)
name:
foreach (Object o that a points to)
genome:
if o is not marked
newactive = newactive U { o }
active = newactive
5 November 2002
CS 201J Fall 2002
name:
genome:
“Elf”
“Frog”
“CGGTG”
19
“CGATG”
Garbage Collection
“in.spc”
Stack
name:
genome:
Bottom of Stack
Phylogeny.main
String[]: args
root: Species
“Duck”
els:
ss: SpeciesSet
Top of Stack
“CATAG”
name:
genome:
active = all objects on stack
“Goat”
while (!active.isEmpty ())
newactive = { }
“CAGTG”
foreach (Object a in active)
mark a as reachable (non-garbage)
name:
foreach (Object o that a points to)
genome:
if o is not marked
newactive = newactive U { o }
active = newactive
5 November 2002
CS 201J Fall 2002
name:
genome:
“Elf”
“Frog”
“CGGTG”
20
“CGATG”
Garbage Collection
“in.spc”
Stack
name:
genome:
Bottom of Stack
Phylogeny.main
String[]: args
root: Species
“Duck”
els:
ss: SpeciesSet
Top of Stack
“CATAG”
name:
genome:
active = all objects on stack
while (!active.isEmpty ())
“Goat”
newactive = { }
foreach (Object a in active)
“CAGTG”
mark a as reachable
foreach (Object o that a points to)
name:
if o is not marked
genome:
newactive = newactive U { o }
active = newactive
sweep () // remove unmarked objects on heap
5 November 2002
CS 201J Fall 2002
name:
genome:
“Elf”
“Frog”
“CGGTG”
21
“CGATG”
After main returns…
“in.spc”
Stack
name:
genome:
Bottom of Stack
Phylogeny.main
String[]: args
root: Species
“Duck”
els:
ss: SpeciesSet
Top of Stack
“CATAG”
name:
genome:
active = all objects on stack
while (!active.isEmpty ())
“Goat”
newactive = { }
foreach (Object a in active)
“CAGTG”
mark a as reachable
foreach (Object o that a points to)
name:
if o is not marked
genome:
newactive = newactive U { o }
active = newactive
sweep () // remove unmarked objects on heap
5 November 2002
CS 201J Fall 2002
name:
genome:
“Elf”
“Frog”
“CGGTG”
22
“CGATG”
Garbage Collection
“in.spc”
Stack
name:
genome:
Bottom
TopofofStack
Stack
“Duck”
els:
“CATAG”
name:
genome:
active = all objects on stack
while (!active.isEmpty ())
“Goat”
newactive = { }
foreach (Object a in active)
“CAGTG”
mark a as reachable
foreach (Object o that a points to)
name:
if o is not marked
genome:
newactive = newactive U { o }
active = newactive
sweep () // remove unmarked objects on heap
5 November 2002
CS 201J Fall 2002
name:
genome:
“Elf”
“Frog”
“CGGTG”
23
“CGATG”
Problems with Mark and Sweep
• Fragmentation: free space and alive
objects will be mixed
– Harder to allocate space for new objects
– Poor locality means bad memory performance
• Caches make it quick to load nearby memory
• Multiple Threads
– One stack per thread, one heap shared by all
threads
– All threads must stop for garbage collection
5 November 2002
CS 201J Fall 2002
24
Stop and Copy
• Solves fragmentation problem
• Copy all reachable objects to a new
memory area
• After copying, reclaim the whole old heap
• Disadvantages:
– More complicated: need to change stack and
internal object pointers to new heap
– Need to save enough memory to copy
– Expensive if most objects are not garbage
5 November 2002
CS 201J Fall 2002
25
Generational Collectors
• Observation:
– Many objects are short-lived
• Temporary objects that get garbage collected right away
– Other objects are long-lived
• Data that lives for the duration of execution
• Separate storage into regions
– Short term: collect frequently
– Long term: collect infrequently
• Stop and copy, but move copies into longer-lived
areas
5 November 2002
CS 201J Fall 2002
26
Reference Counting
What if each object kept track of the
number of references to it?
If the object has zero references, it is garbage!
5 November 2002
CS 201J Fall 2002
27
Referencing Counting
T x = new T ();
The x object has one reference
y = x;
The object x references has 1 more ref
The object ypre references has 1 less ref
}
Leave scope where x is declared
The object x references has 1 less ref
5 November 2002
CS 201J Fall 2002
28
Reference Counting
class Recycle {
private String name; private Vector pals;
public Recycle (String name) { this.name = name; pals = new Vector (); }
public void addPal (Recycle r) { pals.addElement (r); }
“Alice”
}
public class Garbage {
static public void main (String args[]) {
Recycle alice = new Recycle ("alice");
Recycle bob = new Recycle ("bob");
bob.addPal (alice);
alice = new Recycle ("coleen");
bob = new Recycle ("dave");
}
}
5 November 2002
CS 201J Fall 2002
name:
pals:
refs: 21
“Bob”
name:
pals:
refs: 1
29
Reference Counting
class Recycle {
private String name; private Vector pals;
public Recycle (String name) { this.name = name; pals = new Vector (); }
public void addPal (Recycle r) { pals.addElement (r); }
“Alice”
}
public class Garbage {
static public void main (String args[]) {
Recycle alice = new Recycle ("alice");
Recycle bob = new Recycle ("bob");
bob.addPal (alice);
alice = new Recycle ("coleen");
bob = new Recycle ("dave");
“Coleen”
}
}
5 November 2002
name:
pals:
CS 201Jrefs:
Fall 2002
1
name:
pals:
refs: 21
“Bob”
name:
pals:
refs: 1
30
Reference Counting
class Recycle {
private String name; private Vector pals;
public Recycle (String name) { this.name = name; pals = new Vector (); }
public void addPal (Recycle r) { pals.addElement (r); }
“Alice”
}
public class Garbage {
static public void main (String args[]) {
Recycle alice = new Recycle ("alice");
Recycle bob = new Recycle ("bob");
bob.addPal (alice);
alice = new Recycle ("coleen");
bob = new Recycle ("dave");
}
}
5 November 2002
CS 201J Fall 2002
name:
pals:
refs: 01
“Bob”
name:
pals:
refs: 01
31
Circular References
class Recycle {
private String name; private Vector pals;
public Recycle (String name) { this.name = name; pals = new Vector (); }
public void addPal (Recycle r) { pals.addElement (r); }
“Alice”
}
public class Garbage {
static public void main (String args[]) {
Recycle alice = new Recycle ("alice");
Recycle bob = new Recycle ("bob");
bob.addPal (alice);
alice.addPal (bob);
alice = null;
bob = null;
}
}
5 November 2002
CS 201J Fall 2002
name:
pals:
refs: 21
“Bob”
name:
pals:
refs: 1
2
32
Reference Counting Summary
• Advantages
– Can clean up garbage right away when the
last reference is lost
– No need to stop other threads!
• Disadvantages
– Need to store and maintain reference count
– Some garbage is left to fester (circular
references)
– Memory fragmentation
5 November 2002
CS 201J Fall 2002
33
Java’s Garbage Collector
• Mark and Sweep collector
• Before collecting an object, it will call
finalize
protected void finalize() throws Throwable
• Can call garbage collector directly:
System.gc ()
5 November 2002
CS 201J Fall 2002
34
Garbage in, Garbage out?
class Recycle {
private String name; private Vector pals;
public Recycle (String name) { this.name = name; pals = new Vector (); }
public void addPal (Recycle r) { pals.addElement (r); }
protected void finalize () { System.err.println (name + " is garbage!"); }
}
public class Garbage {
static public void main (String args[]) {
Recycle alice = new Recycle ("alice");
Recycle bob = new Recycle ("bob");
bob.addPal (alice);
alice = new Recycle ("coleen");
System.gc ();
bob = new Recycle ("dave");
System.gc ();
}
CS 201J Fall 2002
} 5 November 2002
> java Garbage
First collection:
Second collection:
alice is garbage!
bob is garbage!
35
Testing Strategy
The applicant's source code and documentation shall be reviewed to verify that
the software conforms to the documentation and that the documentation is
sufficient to enable the Division to design and conduct all tests at any level of the
software structure to verify that the software meets the requirements and
objectives of its design specification.
Either the division staff or the ITA, which will conduct software qualification tests,
shall witness compilation of the source code into baseline object code. The
baseline object code and the object code tested must be identical. The object
code tested and certified must be identical to the object code released. A copy of
the baseline object code will be retained by the Division and used to verify that
the baseline code, tested code, and the release code are identical.
Once the Division has conducted a review of system software and
documentation, test plans shall be designed to exercise all system functions
controlled by software under nominal load and data conditions and throughout
the range of conditions for which performance is claimed. The first phase of
Florida Software Qualification Testing is designed to evaluate the system
software’s functionality, and to establish baselines for the system being
tested. …
Florida Voting Systems Standard,
5 November 2002
CS 201J Fall 2002
http://election.dos.state.fl.us/laws/pdf/FVSS402.pdf
36
Election Day
• How much do you trust the programs in
the voting machines to record your vote
correctly?
• How much do you trust the programs that
tabulate the votes to count them correctly?
Hint #1: These programs were probably written in C.
Hint #2: These programs were probably not written by Libertarians.
Hint #3: The authors of these programs didn’t pass CS201J and
weren’t able to get more interesting, high-paying programming
jobs.
5 November 2002
CS 201J Fall 2002
37
Charge
• In Java: be happy you
have a garbage collector
to clean up for you
• In C: need to deallocate
storage explicitly
– Why is it hard to write a
garbage collector for C?
(next class)
• In the real world: clean up
after yourself and others!
5 November 2002
CS 201J Fall 2002
Garbage Collectors
(COAX, Seoul, 18 June 2002)
38