Class 24: Garbage Collection

Slides:



Advertisements
Similar presentations
Dynamic Memory Management
Advertisements

Introduction to Memory Management. 2 General Structure of Run-Time Memory.
CMSC 330: Organization of Programming Languages Memory and Garbage Collection.
Lecture 10: Heap Management CS 540 GMU Spring 2009.
CMSC 330: Organization of Programming Languages Memory and Garbage Collection.
Fall 2010 UVa David Evans cs2220: Engineering Software Class 24: Garbage Collection flickr cc: kiksbalayon.
June 1, 2000 Object Oriented Programming in Java (95-707) Java Language Basics 1 Lecture 6 Object Oriented Programming in Java Language Basics Objects.
Memory Management Tom Roeder CS fa. Motivation Recall unmanaged code eg C: { double* A = malloc(sizeof(double)*M*N); for(int i = 0; i < M*N; i++)
Garbage Collection CSCI 2720 Spring Static vs. Dynamic Allocation Early versions of Fortran –All memory was static C –Mix of static and dynamic.
David Evans CS201j: Engineering Software University of Virginia Computer Science Lecture 21: Garbage Collection.
CS 326 Programming Languages, Concepts and Implementation Instructor: Mircea Nicolescu Lecture 18.
CPSC 388 – Compiler Design and Construction
CS 536 Spring Automatic Memory Management Lecture 24.
Chapter 8 Runtime Support. How program structures are implemented in a computer memory? The evolution of programming language design has led to the creation.
Memory Management. History Run-time management of dynamic memory is a necessary activity for modern programming languages Lisp of the 1960’s was one of.
Memory Allocation and Garbage Collection. Why Dynamic Memory? We cannot know memory requirements in advance when the program is written. We cannot know.
JVM-1 Introduction to Java Virtual Machine. JVM-2 Outline Java Language, Java Virtual Machine and Java Platform Organization of Java Virtual Machine Garbage.
Linked lists and memory allocation Prof. Noah Snavely CS1114
Reference Counters Associate a counter with each heap item Whenever a heap item is created, such as by a new or malloc instruction, initialize the counter.
Programming Languages: Design, Specification, and Implementation G Rob Strom October 19, 2006.
COMP 14: Intro. to Intro. to Programming May 23, 2000 Nick Vallidis.
SEG Advanced Software Design and Reengineering TOPIC L Garbage Collection Algorithms.
CS216: Program and Data Representation University of Virginia Computer Science Spring 2006 David Evans Lecture 25 There.
Dynamic Memory Allocation Questions answered in this lecture: When is a stack appropriate? When is a heap? What are best-fit, first-fit, worst-fit, and.
Lecture 10 : Introduction to Java Virtual Machine
1 Names, Scopes and Bindings Aaron Bloomfield CS 415 Fall
Chapter 3.5 Memory and I/O Systems. 2 Memory Management Memory problems are one of the leading causes of bugs in programs (60-80%) MUCH worse in languages.
Storage Management. The stack and the heap Dynamic storage allocation refers to allocating space for variables at run time Most modern languages support.
David Evans CS201j: Engineering Software University of Virginia Computer Science Lecture 17: Garbage Collection.
1 Records Record aggregate of data elements –Possibly heterogeneous –Elements/slots are identified by names –Elements in same fixed order in all records.
Copyright Curt Hill Variables What are they? Why do we need them?
1 Languages and Compilers (SProg og Oversættere) Heap allocation and Garbage Collection.
Garbage Collection and Classloading Java Garbage Collectors  Eden Space  Surviver Space  Tenured Gen  Perm Gen  Garbage Collection Notes Classloading.
Heap storage & Garbage collection Programming Language Design and Implementation (4th Edition) by T. Pratt and M. Zelkowitz Prentice Hall, 2001.
Garbage Collection and Memory Management CS 480/680 – Comparative Languages.
G ARBAGE C OLLECTION CSCE-531 Ankur Jain Neeraj Agrawal 1.
CSE 374 Programming Concepts & Tools Hal Perkins Fall 2015 Lecture 10 – C: the heap and manual memory management.
1 Lecture07: Memory Model 5/2/2012 Slides modified from Yin Lou, Cornell CS2022: Introduction to C.
Consider Starting with 160 k of memory do: Starting with 160 k of memory do: Allocate p1 (50 k) Allocate p1 (50 k) Allocate p2 (30 k) Allocate p2 (30 k)
CS412/413 Introduction to Compilers and Translators April 21, 1999 Lecture 30: Garbage collection.
Reference Types CSE301 University of Sunderland Harry R Erwin, PhD.
CS216: Program and Data Representation University of Virginia Computer Science Spring 2006 David Evans Lecture 12: Automating Memory Management
Object Lifetime and Pointers
Garbage Collection What is garbage and how can we deal with it?
Core Java Garbage Collection LEVEL – PRACTITIONER.
Topic: Java Garbage Collection
CSE 374 Programming Concepts & Tools
Dynamic Memory Allocation
Storage Management.
Run-time organization
Lecture 2 Memory management.
Concepts of programming languages
Automatic Memory Management
Optimizing Malloc and Free
Storage.
Lecture 15: Concurring Concurrently CS201j: Engineering Software
Smart Pointers.
Strategies for automatic memory management
Memory Allocation CS 217.
Binding Times Binding is an association between two things Examples:
Stacks.
Lecture 18: Deep C Garbage Collection CS201j: Engineering Software
Created By: Asst. Prof. Ashish Shah, J.M.Patel College, Goregoan West
Heap storage & Garbage collection
CSE 153 Design of Operating Systems Winter 2019
Heap storage & Garbage collection
Garbage collection Programming Language Design and Implementation (4th Edition) by T. Pratt and M. Zelkowitz Prentice Hall, 2001 Section
Exception Handling.
Automating Memory Management
Garbage Collection What is garbage and how can we deal with it?
Presentation transcript:

Class 24: Garbage Collection cs2220: Engineering Software Class 24: Garbage Collection Fall 2010 UVa David Evans flickr cc: kiksbalayon

Menu Memory review: Stack and Heap Garbage Collection Mark and Sweep Stop and Copy Reference Counting Java’s Garbage Collector

Exam 2 Out Thursday, due next Tuesday Coverage: anything in the class up to last lecture Main Topics Type Hierarchy: Subtyping, Inheritance, Dynamic Dispatch, behavioral subtyping rules, substitution principle Concurrency abstraction: multi-threading, race conditions, deadlocks Java Security: bytecode verification, code safety, policy enforcement You will have 5 days for Exam 2, but it is designed to be short enough that you should still have plenty time to work on your projects while Exam 2 is out.

When do the stack and heap look like this? Stack and Heap Review Stack Heap public class Strings { public static void test () { StringBuffer sb = new StringBuffer("hello"); } static public void main (String args[]) { test (); A B sb 1 java.lang.StringBuffer 2 “hello” 3 When do the stack and heap look like this?

Stack and Heap Review sb “hello” Heap Stack public class Strings { public static void test () { StringBuffer sb = new StringBuffer ("hello"); } static public void main (String args[]) { test (); B sb java.lang.StringBuffer “hello” 2

Garbage Heap “hello” “hello” “hello” “hello” “hello” “hello” “hello” 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”

Explicit Memory Management C/C++: programmer uses free (pointer) to indicate that the storage pointer points to should be reclaimed. public class Strings { public static void test () { StringBuffer sb = new StringBuffer ("hello"); free (sb); } static public void main (String args[]) { while (true) test (); Very painful! Missing free: memory leak Dangling references: to free’d objects

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?

Mark and Sweep

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 In a Java execution, what are the root references? References on the stack.

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 ArrayList<Species> els; public void insert (Species s) { if (getIndex (s) < 0) els.add (s);

“in.spc” Stack Bottom of Stack name: genome: String[]: args Phylogeny.main String[]: args root: Species “Duck” els: ss: SpeciesSet “CATAG” name: genome: current: Species SpeciesSet.insert “Goat” this: SpeciesSet “CAGTG” s: Species Top of Stack name: genome: name: genome: 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 ArrayList<Species> els; public void insert (Species s) { if (getIndex (s) < 0) els.add (s); } } “Frog” “Elf” “CGATG” “CGGTG”

After els.add (s)… “in.spc” Stack Bottom of Stack name: genome: Phylogeny.main String[]: args root: Species “Duck” els: ss: SpeciesSet “CATAG” name: genome: current: Species SpeciesSet.insert “Goat” this: SpeciesSet “CAGTG” s: Species Top of Stack name: genome: name: genome: 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 ArrayList<Species> els; public void insert (Species s) { if (getIndex (s) < 0) els.add (s); } } “Frog” “Elf” “CGATG” “CGGTG”

SpeciesSet.insert returns… “in.spc” Stack Bottom of Stack name: genome: Phylogeny.main String[]: args root: Species “Duck” els: ss: SpeciesSet “CATAG” name: genome: current: Species SpeciesSet.insert “Goat” this: SpeciesSet “CAGTG” s: Species Top of Stack name: genome: name: genome: 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 ArrayList<Species> els; public void insert (Species s) { if (getIndex (s) < 0) els.add (s); } } “Frog” “Elf” “CGATG” “CGGTG”

Finish while loop… “in.spc” Stack Bottom of Stack name: genome: Phylogeny.main String[]: args root: Species “Duck” els: ss: SpeciesSet “CATAG” name: genome: current: Species Top of Stack “Goat” “CAGTG” name: genome: name: genome: 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 ArrayList<Species> els; public void insert (Species s) { if (getIndex (s) < 0) els.add (s); } } “Frog” “Elf” “CGATG” “CGGTG”

Garbage Collection “in.spc” Stack Bottom of Stack name: genome: Phylogeny.main String[]: args root: Species “Duck” els: ss: SpeciesSet “CATAG” Top of Stack name: genome: “Goat” “CAGTG” name: genome: name: genome: 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 ArrayList<Species> els; public void insert (Species s) { if (getIndex (s) < 0) els.add (s); } } “Frog” “Elf” “CGATG” “CGGTG”

Initialize Mark and Sweeper: active = all objects on stack Garbage Collection “in.spc” Stack Bottom of Stack name: genome: Phylogeny.main String[]: args root: Species “Duck” els: ss: SpeciesSet “CATAG” Top of Stack name: genome: “Goat” Initialize Mark and Sweeper: active = all objects on stack “CAGTG” name: genome: name: genome: “Frog” “Elf” “CGATG” “CGGTG”

Mark and Sweep Algorithm

Mark and Sweep Algorithm active = all objects on stack while (!active.isEmpty ()) newactive = { } foreach (Object a in active) mark a as reachable (non-garbage) foreach (Object o that a points to) if o is not marked newactive = newactive U { o } active = newactive

active = all objects on stack while (!active.isEmpty ()) Garbage Collection “in.spc” Stack Bottom of Stack name: genome: Phylogeny.main String[]: args root: Species “Duck” els: ss: SpeciesSet “CATAG” Top of Stack name: genome: active = all objects on stack while (!active.isEmpty ()) newactive = { } foreach (Object a in active) mark a as reachable (non-garbage) foreach (Object o that a points to) if o is not marked newactive = newactive U { o } active = newactive “Goat” “CAGTG” name: genome: name: genome: “Frog” “Elf” “CGATG” “CGGTG”

active = all objects on stack while (!active.isEmpty ()) Garbage Collection “in.spc” Stack Bottom of Stack name: genome: Phylogeny.main String[]: args root: Species “Duck” els: ss: SpeciesSet “CATAG” Top of Stack name: genome: active = all objects on stack while (!active.isEmpty ()) newactive = { } foreach (Object a in active) mark a as reachable (non-garbage) foreach (Object o that a points to) if o is not marked newactive = newactive U { o } active = newactive “Goat” “CAGTG” name: genome: name: genome: “Frog” “Elf” “CGATG” “CGGTG”

active = all objects on stack while (!active.isEmpty ()) Garbage Collection “in.spc” Stack Bottom of Stack name: genome: Phylogeny.main String[]: args root: Species “Duck” els: ss: SpeciesSet “CATAG” Top of Stack name: genome: active = all objects on stack while (!active.isEmpty ()) newactive = { } foreach (Object a in active) mark a as reachable (non-garbage) foreach (Object o that a points to) if o is not marked newactive = newactive U { o } active = newactive “Goat” “CAGTG” name: genome: name: genome: “Frog” “Elf” “CGATG” “CGGTG”

active = all objects on stack while (!active.isEmpty ()) Garbage Collection “in.spc” Stack Bottom of Stack name: genome: Phylogeny.main String[]: args root: Species “Duck” els: ss: SpeciesSet “CATAG” Top of Stack name: genome: active = all objects on stack while (!active.isEmpty ()) newactive = { } foreach (Object a in active) mark a as reachable (non-garbage) foreach (Object o that a points to) if o is not marked newactive = newactive U { o } active = newactive “Goat” “CAGTG” name: genome: name: genome: “Frog” “Elf” “CGATG” “CGGTG”

active = all objects on stack while (!active.isEmpty ()) Garbage Collection “in.spc” Stack Bottom of Stack name: genome: Phylogeny.main String[]: args root: Species “Duck” els: ss: SpeciesSet “CATAG” Top of Stack name: genome: active = all objects on stack while (!active.isEmpty ()) newactive = { } foreach (Object a in active) mark a as reachable (non-garbage) foreach (Object o that a points to) if o is not marked newactive = newactive U { o } active = newactive “Goat” “CAGTG” name: genome: name: genome: “Frog” “Elf” “CGATG” “CGGTG”

active = all objects on stack while (!active.isEmpty ()) Garbage Collection “in.spc” Stack Bottom of Stack name: genome: Phylogeny.main String[]: args root: Species “Duck” els: ss: SpeciesSet “CATAG” Top of Stack name: genome: active = all objects on stack while (!active.isEmpty ()) newactive = { } foreach (Object a in active) mark a as reachable (non-garbage) foreach (Object o that a points to) if o is not marked newactive = newactive U { o } active = newactive sweep () // remove unmarked objects on heap “Goat” “CAGTG” name: genome: name: genome: “Frog” “Elf” “CGATG” “CGGTG”

active = all objects on stack while (!active.isEmpty ()) After main returns… “in.spc” Stack Bottom of Stack name: genome: Phylogeny.main String[]: args root: Species “Duck” els: ss: SpeciesSet “CATAG” Top of Stack name: genome: active = all objects on stack while (!active.isEmpty ()) newactive = { } foreach (Object a in active) mark a as reachable (non-garbage) foreach (Object o that a points to) if o is not marked newactive = newactive U { o } active = newactive sweep () // remove unmarked objects on heap “Goat” “CAGTG” name: genome: name: genome: “Frog” “Elf” “CGATG” “CGGTG”

active = all objects on stack while (!active.isEmpty ()) Garbage Collection “in.spc” Stack Bottom of Stack name: genome: Top of Stack “Duck” els: “CATAG” name: genome: active = all objects on stack while (!active.isEmpty ()) newactive = { } foreach (Object a in active) mark a as reachable (non-garbage) foreach (Object o that a points to) if o is not marked newactive = newactive U { o } active = newactive sweep () // remove unmarked objects on heap “Goat” “CAGTG” name: genome: name: genome: “Frog” “Elf” “CGATG” “CGGTG”

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

Stop and Copy Stop execution Identify all reachable objects (as in Mark and Sweep) Copy all reachable objects to a new memory area After copying, reclaim the whole old heap Solves fragmentation problem 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

Generational Collectors Observation: Most 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

Reference Counting What if each object kept track of the number of references to it? If the object has zero references, it is garbage!

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); } } 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"); “Alice” name: pals: refs: 2 1 “Bob” name: pals: refs: 1

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); } } 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"); “Alice” name: pals: refs: 2 1 “Coleen” “Bob” name: pals: refs: name: pals: refs: 1 1

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); } } 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"); “Alice” name: pals: refs: 1 “Bob” name: pals: refs: 1

Can reference counting ever fail to reclaim unreachable storage?

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); } } 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; “Alice” name: pals: refs: 1 “Bob” name: pals: refs: 1

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

Java’s Garbage Collector Mark and Sweep collector Generational Can call garbage collector directly: System.gc () but, this should hardly ever be done (except for “fun”) Python’s Garbage Collector Reference counting: To quickly reclaim most storage Mark and sweep collector (optional, but on by default): To collect circular references

java.lang.Object.finalize() protected void finalize() throws Throwable Called by the garbage collector on an object when garbage collection determines that there are no more references to the object. A subclass overrides the finalize method to dispose of system resources or to perform other cleanup. The general contract of finalize is that it is invoked if and when the JavaTM virtual machine has determined that there is no longer any means by which this object can be accessed by any thread that has not yet died, except as a result of an action taken by the finalization of some other object or class which is ready to be finalized. The finalize method may take any action, including making this object available again to other threads; the usual purpose of finalize, however, is to perform cleanup actions before the object is irrevocably discarded. For example, the finalize method for an object that represents an input/output connection might perform explicit I/O transactions to break the connection before the object is permanently discarded. The finalize method of class Object performs no special action; it simply returns normally. Subclasses of Object may override this definition. The Java programming language does not guarantee which thread will invoke the finalize method for any given object. It is guaranteed, however, that the thread that invokes finalize will not be holding any user-visible synchronization locks when finalize is invoked. If an uncaught exception is thrown by the finalize method, the exception is ignored and finalization of that object terminates. After the finalize method has been invoked for an object, no further action is taken until the Java virtual machine has again determined that there is no longer any means by which this object can be accessed by any thread that has not yet died, including possible actions by other objects or classes which are ready to be finalized, at which point the object may be discarded. The finalize method is never invoked more than once by a Java virtual machine for any given object. Any exception thrown by the finalize method causes the finalization of this object to be halted, but is otherwise ignored. Summary: finalize is called when garbage collector reclaims object no guarantee when it will be called after finalizer, JVM has to check you didn’t do something stupid its protected because subclasses need to override it (but no one other than the JVM itself should ever call it!) You should probably never need to override finalize in your code. Only excuse for using it is if you have objects with unknown lifetimes that have associated (non-memory) resources.

> java Garbage First collection: Second collection: class Recycle { private String name; private ArrayList<Recycle> pals; public Recycle (String name) { this.name = name; pals = new ArrayList<Recycle> (); } public void addPal (Recycle r) { pals.add (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.out.println("First collection:"); System.gc (); bob = new Recycle ("dave"); System.out.println("Second collection:"); > java Garbage First collection: Second collection: alice is garbage! bob is garbage!

Note running the garbage collector itself uses memory! class Recycle { private String name; private ArrayList<Recycle> pals; public Recycle (String name) { this.name = name; pals = new ArrayList<Recycle> (); } public void addPal (Recycle r) { pals.add (r); } protected void finalize () { System.err.println (name + " is garbage!"); } } public class Garbage { static public void main (String args[]) { System.err.println(Runtime.getRuntime().freeMemory() + " bytes free!"); Recycle alice = new Recycle ("alice"); Recycle bob = new Recycle ("bob"); bob.addPal (alice); alice = new Recycle ("coleen"); System.err.println("First collection:"); System.gc (); bob = new Recycle ("dave"); System.err.println("Second collection:"); 125431952 bytes free! First collection: 125933456 bytes free! Second collection: 125933216 bytes free! bob is garbage! alice is garbage! Note running the garbage collector itself uses memory!

class Recycle { private String name; private ArrayList<Recycle> pals; public Recycle (String name) { this.name = name; pals = new ArrayList<Recycle> (); } public void addPal (Recycle r) { pals.add (r); } protected void finalize () { Garbage.truck = this; System.err.println (name + " is garbage!" + this.hashCode()); } } public class Garbage { static public Recycle truck; static public void main (String args[]) { printMemory(); while (true) { Recycle alice = new Recycle ("alice"); System.gc ();

Charge In Java: be happy you have a garbage collector to clean up for you In C/C++: need to deallocate storage explicitly Why is it hard to write a garbage collector for C? In the real world: clean up after yourself and others! Keep working on your projects Exam 2 out Thursday Garbage Collectors (COAX, Seoul, 18 June 2002)