Memory Management. Memory Management... Memory Management... Interface to Dynamic allocation

Similar documents
Lecture 13: Garbage Collection

G Programming Languages - Fall 2012

CMSC 330: Organization of Programming Languages

Deallocation Mechanisms. User-controlled Deallocation. Automatic Garbage Collection

CS 345. Garbage Collection. Vitaly Shmatikov. slide 1

Automatic Garbage Collection

CMSC 330: Organization of Programming Languages

Run-Time Environments/Garbage Collection

Heap Management. Heap Allocation

Memory Allocation. Static Allocation. Dynamic Allocation. Dynamic Storage Allocation. CS 414: Operating Systems Spring 2008

Runtime. The optimized program is ready to run What sorts of facilities are available at runtime

CMSC 330: Organization of Programming Languages. Memory Management and Garbage Collection

One-Slide Summary. Lecture Outine. Automatic Memory Management #1. Why Automatic Memory Management? Garbage Collection.

Lecture 13: Complex Types and Garbage Collection

CS61C : Machine Structures

Garbage Collection. Akim D le, Etienne Renault, Roland Levillain. May 15, CCMP2 Garbage Collection May 15, / 35

Automatic Memory Management

Sustainable Memory Use Allocation & (Implicit) Deallocation (mostly in Java)

Example. program sort; var a : array[0..10] of integer; procedure readarray; : function partition (y, z :integer) :integer; var i, j,x, v :integer; :

6.172 Performance Engineering of Software Systems Spring Lecture 9. P after. Figure 1: A diagram of the stack (Image by MIT OpenCourseWare.

Acknowledgements These slides are based on Kathryn McKinley s slides on garbage collection as well as E Christopher Lewis s slides

Programming Language Implementation

Compiler Construction

CS 4120 Lecture 37 Memory Management 28 November 2011 Lecturer: Andrew Myers

Memory Management. Didactic Module 14 Programming Languages - EEL670 1

Memory Management. Chapter Fourteen Modern Programming Languages, 2nd ed. 1

Compiler Construction

Design Issues. Subroutines and Control Abstraction. Subroutines and Control Abstraction. CSC 4101: Programming Languages 1. Textbook, Chapter 8

Garbage Collection. Hwansoo Han

CS61C : Machine Structures

Lecture Notes on Advanced Garbage Collection

CA341 - Comparative Programming Languages

Garbage Collection Algorithms. Ganesh Bikshandi

Compilers. 8. Run-time Support. Laszlo Böszörmenyi Compilers Run-time - 1

Garbage Collection (1)

CS 536 Introduction to Programming Languages and Compilers Charles N. Fischer Lecture 11

ACM Trivia Bowl. Thursday April 3 rd (two days from now) 7pm OLS 001 Snacks and drinks provided All are welcome! I will be there.

Manual Allocation. CS 1622: Garbage Collection. Example 1. Memory Leaks. Example 3. Example 2 11/26/2012. Jonathan Misurda

Compiler Construction D7011E

A.Arpaci-Dusseau. Mapping from logical address space to physical address space. CS 537:Operating Systems lecture12.fm.2

Performance of Non-Moving Garbage Collectors. Hans-J. Boehm HP Labs

Dynamic Storage Allocation

CS61C : Machine Structures

Lecture Notes on Garbage Collection

CS61C : Machine Structures

CS577 Modern Language Processors. Spring 2018 Lecture Garbage Collection

Principles of Programming Languages Topic: Scope and Memory Professor Louis Steinberg Fall 2004

Data Types. Outline. In Text: Chapter 6. What is a type? Primitives Strings Ordinals Arrays Records Sets Pointers 5-1. Chapter 6: Data Types 2

Run-time Environments -Part 3

Run-time Environments - 3

CSC 1600 Memory Layout for Unix Processes"

Lecture Notes on Garbage Collection

In Java we have the keyword null, which is the value of an uninitialized reference type

Memory Management and Run-Time Systems

Data Types In Text: Ch C apter 6 1

Structure of Programming Languages Lecture 10

Concepts Introduced in Chapter 7

Process s Address Space. Dynamic Memory. Backing the Heap. Dynamic memory allocation 3/29/2013. When a process starts the heap is empty

Lecture 7 More Memory Management Slab Allocator. Slab Allocator

Lecture 23: Object Lifetime and Garbage Collection

Lecture 15 Garbage Collection

Programming Languages

CS 241 Honors Memory

Simple Garbage Collection and Fast Allocation Andrew W. Appel

Reference Counting. Reference counting: a way to know whether a record has other users

Garbage Collection Techniques

Managed runtimes & garbage collection. CSE 6341 Some slides by Kathryn McKinley

Reference Counting. Reference counting: a way to know whether a record has other users

Programming Languages Third Edition. Chapter 10 Control II Procedures and Environments

Garbage Collection. Weiyuan Li

Managed runtimes & garbage collection

Exploiting the Behavior of Generational Garbage Collector

Lecture 7: Binding Time and Storage

Dynamic Memory Allocation. Basic Concepts. Computer Organization 4/3/2012. CSC252 - Spring The malloc Package. Kai Shen

CS61C : Machine Structures

CSE P 501 Compilers. Memory Management and Garbage Collec<on Hal Perkins Winter UW CSE P 501 Winter 2016 W-1

Dynamic Memory Allocation

(notes modified from Noah Snavely, Spring 2009) Memory allocation

o Code, executable, and process o Main memory vs. virtual memory

Motivation for Dynamic Memory. Dynamic Memory Allocation. Stack Organization. Stack Discussion. Questions answered in this lecture:

CSc 520 Principles of Programming Languages

Binding and Storage. COMP 524: Programming Language Concepts Björn B. Brandenburg. The University of North Carolina at Chapel Hill

CSc 520 Principles of Programming Languages. ameter Passing Reference Parameter. Call-by-Value Parameters. 28 : Control Structures Parameters

CSCI-1200 Data Structures Fall 2011 Lecture 24 Garbage Collection & Smart Pointers

Garbage Collection. CS 351: Systems Programming Michael Saelee

Robust Memory Management Schemes

[Muller76] Muller, K.G. On the feasibility of concurrent garbage collection. Ph.D. thesis, Tech. Hogeschool Delft, The Netherlands, March 1976.

Algorithms for Dynamic Memory Management (236780) Lecture 1

Heap storage. Dynamic allocation and stacks are generally incompatible.

Memory management COSC346

CPSC 213. Introduction to Computer Systems. Winter Session 2017, Term 2. Unit 1c Jan 24, 26, 29, 31, and Feb 2

10.1. CS356 Unit 10. Memory Allocation & Heap Management

Older geometric based addressing is called CHS for cylinder-head-sector. This triple value uniquely identifies every sector.

Algorithms for Dynamic Memory Management (236780) Lecture 4. Lecturer: Erez Petrank

first class citizens

Chapter 8 :: Composite Types

Concurrent garbage collection for C++

Dynamic Memory Management

NOTE: Answer ANY FOUR of the following 6 sections:

Lecture 8 Dynamic Memory Allocation

Transcription:

CSc 453 Compilers and Systems Software 24 : Garbage Collection Introduction Department of Computer Science University of Arizona collberg@gmail.com Copyright c 2009 Christian Collberg Dynamic Memory Management The run-time system linked in with the generated code should contain routines for allocation/deallocation of dynamic memory. Pascal, C, C++, Modula-2 Explicit deallocation of dynamic memory only. I.e. the programmer is required to keep track of all allocated memory and when it s safe to free it. Eiffel Implicit deallocation only. Dynamic memory which is no longer used is recycled by the garbage collector. Ada Implicit or explicit deallocation (implementation defined). Modula-3 Implicit and explicit deallocation (programmer s choice). Memory Management

Memory Management Memory Management... In a language such as C or Pascal, there are three ways to allocate memory: 1 Static allocation. Global variables are allocated at compile time, by reserving 2 Stack allocation. The stack is used to store activation records, which holds procedure call chains and local variables. 3 Dynamic allocation. The user can create new memory at will, by calling a new or (in unix) malloc procedure. The compiler and run-time system divide the available address space (memory) into three sections, one for each type of allocation: 1 The static section is generated by the compiler and cannot be extended at run-time. Called the uninitialized data section in unix s a.out. 2 The stack. The stack grows and shrinks during execution, according to the depth of the call chain. Infinite recursion often leads to stack overflow. Large parameters can also result in the program running out of stack space. 3 The heap. When the program makes a request for more dynamic memory (by calling malloc, for example), a suitable chunk of memory is allocated on the heap. Memory Management... Interface to Dynamic allocation Static allocation Global variables Stack allocation Procedure call chains, Local variables. Dynamic allocation NEW, malloc, On the heap. Program Code Initialized Data (strings,reals...) Uninitialized Data (Global Variables) Stack Heap C, C++: char* malloc(size) and free(char*) are standard library routines. Pascal: new(pointer var) and dispose(pointer var) are builtin standard procedures. Java: new(class name) is a standard function. LISP: cons creates new cells: Head b Tail (cons a (b c)) a b c null (b c) (a b c) c null

Explicit Deallocation Explicit Deallocation Pascal s new/dispose, Modula-2 s ALLOCATE/DEALLOCATE, C s malloc/free, C++ s new/delete, Ada s new/unchecked deallocation (some implementations). Problem 1: Dangling references: p=malloc(); q=p; free(p);. Problem 2: Memory leaks, Heap fragmentation. Small cell free list: 4 8 16 32 64 Heap: Large cell free list: 128 512 Implicit Deallocation Implicit Deallocation LISP, Prolog Equal-sized cells; No changes to old cells. Eiffel, Modula-3 Different-sized cells; Frequent changes to old cells. When do we GC? Stop-and-copy Perform a GC whenever we run out of heapspace (Modula-3). Real-time/Incremental Perform a partial GC for each pointer assignment or new (Eiffel, Modula-3). Concurrent Run the GC in a separate process.

Implicit Deallocation... Fragmentation Compact the heap as a part of the GC, or only when the GC fails to return a large enough block. Algorithms: Reference counts, Mark/ssweep, Copying, Generational. Garbage Collection Problems Finding the Object Graph Finding the roots: The dynamic objects in a program form a graph. Most GC algorithms need to traverse this graph. The roots of the graph can be in 1 global variables 2 registers 3 local variables/formal parameters on the stack. Hence, the compiler must communicate to the GC which registers/variables contain roots. Finding internal pointers: Structured variables (arrays, records, objects) may contain internal pointers. These must be known to the GC so that it can traverse the graph. Hence, the compiler must communicate to the GC the type of each dynamic object and the internal structure of each type. Finding the beginning of objects: What happens if the only pointer to an object points somewhere in the middle of the object? We must either be able to find the beginning of the object, or make sure the compiler does not generate such code.

8: Pointer Maps Execution Globals Heap Stack template AR for A P G O: template 8: Ptrs: [12] Size:96 Template for P AR for Q AR for R %r8 C O: template 8: 12: O: template Ptrs: [0] Size:4 Template for MAIN Ptrs: [4,12] Size:32 Template for T1 Ptrs: [8] Size: 24 The internal structure of activation records & structured variables is described by run-time templates. Every run-time object has an extra word that points to a type descriptor (or Temaplate), a structure describing which words in the object are pointers. This map is constructed at compile-time and stored statically in the data segment of the executable. Template for T2 Pointer Maps... Pointer Maps... When the GC is invoked, registers may also contain valid pointers. The compiler must therefore also generate (for every point where the GC may be called) a pointer map that describes which registers hold live pointers at this point. For this reason, we usually only allow the GC to run at certain points, often the points where new is called. We must also provide pointer maps for every function call point. A function P may call Q which calls new which invokes the GC. We need to know which words in P s activation record that at this point contain live pointers. How does the GC look up which pointer map belongs to a particular call to procedure P at a particular address a? The pointer maps are indexed by the return address of P! So, to traverse the stack of activation records, the GC looks at each frame, extracts the return address, finds the pointer map for that address, and extracts each pointer according to the map.

Algorithm: Reference Counts GC Algorithms: Reference Counts An extra field is kept in each object containing a count of the number of pointers which point to the object. Each time a pointer is made to point to an object, that object s count has to be incremented. Similarly, every time a pointer no longer points to an object, that object s count has to be decremented. When we run out of dynamic memory we scan through the heap and put objects with a zero reference count back on the free-list. Maintaining the reference count is costly. Also, circular structures (circular linked lists, for example) will not be collected. Every object records the number of pointers pointing to it. When a pointer changes, the corresponding object s reference count has to be updated. GC: reclaim objects with a zero count. Circular structures will not be reclaimed. Global Variables a b Live cells 1 2 1 1 0 1 Garbage (will be reclaimed) 1 Garbage (won t be reclaimed) H e a p NEW(p) is implemented as: malloc(p); p.rc := 0; p.next:=q is implemented as: z := p.next; if z nil then z.rc--; if z.rc = 0 then reclaim z endif; endif; p.next := q; q.rc++; This code sequence has to be inserted by the compiler for every pointer assignment in the program. This is very expensive.

Algorithm: Mark and Sweep GC Algorithms: Mark-and-Sweep The basic idea behind Mark-and-Sweep is to traverse and mark all the cells that can be reached from the root cells. A root cell is any pointer on the stack or in global memory which points to objects on the heap. Once all the live cells (those which are pointed to by a global variable or some other live cells) have been marked, we scan through the heap and separate the live data from the garbage. If we are dealing with equal size objects only (this is the case in LISP, for example) the we scan the heap and link all the unmarked objects onto the free list. At the same time we can unmark the live cells. Algorithm: Mark and Sweep... If we have cells of different sizes, just linking the freed objects together may result in heap fragmentation. Instead we need to compact the heap, by collecting live cells together in a contiguous memory area on the heap and doing the same with the garbage cells in another area. 1 Mark all objects unmarked. Marking Phase: 2 Find all roots, i.e. heap pointers in stack, regs & globals. 3 Mark reachable blocks using a depth first search starting at the roots. 1 DFS may run out of stack space! 2 Use non-recursive (Deutsch-Schorr-Waite) DFS. Scanning Phase: same-size-cells Scan heap and put un-marked (non-reachable) cells back on free-list. different-size-cells Compact the heap to prevent fragmentation.

Marking Phase Marking Phase A straight-forward implementation of mark and sweep may run into memory problems itself! A depth-first-search makes use of a stack, and the size of the stack will be the same as the depth of the object graph. Remember that the stack and the heap share the same memory space, and may even grow towards eachother. So, if we re out of luck we might run into this situation: the heap is full (otherwise we wouldn t be gc:ing!), the object graph is deep, we run out of stack space during the marking phase. We re now out of memory alltogether. Difficult to recover from! Marking Phase... Marking: Look Ma, No Stack! Fortunately, there is a smart algorithm for marking in constant space, called the Deutsch-Schorr-Waite algorithm. Actually, it was developed simultaneously by Peter Deutsch and by Herbert Schorr and W. M. Waite. The basic idea is to store the DFS stack in the object graph itself. When a new node (object) is encountered 1 we set the marked -bit to 1, 2 the node (object) is made to point to the previous node, 3 two global variables current and previous are updated. current points to the current cell, previous to the previously visited cell. Use pointer reversal to encode the DFS stack in the object graph itself. When the DFS reaches a new cell, change a pointer in the cell to point back to the DFS parent cell. When we can go no deeper, return, following the back links, restoring the links. (1) (1) M (2) (4) / (3) (2) (3) / B B (4) M (5) / / (5) / / M / / B = Back Pointer M = Marked previous current M

Sweeping: Compaction data1 data2 data3 Compaction Phase A B C D E data1 data2 data3 Compaction F A B C D E F 1 Calculate the forwarding address of each cell. 2 Store the forwarding address of cell B in B.forw addr. 3 If p points to cell B, replace p with B.forw addr. 4 Move all cells to their forwarding addresses. Copying Collection GC Algorithms: Copying Collection Even if most of the heapspace is garbage, a mark and sweep algorithm will touch the entire heap. In such cases it would be better if the algorithm only touched the live objects. Copying collection is such an algorithm. The basic idea is: 1 The heap is divided into two spaces, the from-space and the to-space. 2 We start out by allocating objects in the from-space. 3 When from-space is full, all live objects are copied from from-space to to-space. 4 We then continue allocating in to-space until it fills up, and a new GC starts.

Copying Collection... Copying Collection... An important side-effect of copying collection is that we get automatic compaction after a collection to-space consists of the live objects in a contiguous piece of memory, followed by the free space. This sounds really easy, but : We have to traverse the object graph (just like in mark and sweep), and so we need to decide the order in which this should be done, depth-first or breadth-first. DFS requires a stack (but we can, of course, use pointer reversal just as with mark and sweep), and BFS a queue. We will see later that encoding a queue is very simple, and hence most implementations of copying collection make use of BFS. This sounds really easy, but An object in from-space will generally have several objects pointing to it. So, when an object is moved from from-space to to-space we have to make sure that we change the pointers to point to the new copy. Copying Collection... Mark-and-sweep touches the entire heap, even if most of it is garbage. Copying collection only touches live cells. Copying collection divides the heap in two parts: from-space and to-space. to-space is automatically compacted. How to traverse object graph: BFS or DFS? How to update pointers to moved objects? Algorithm: 1 Start allocating in from-space. 2 When from-space is full, copy live objects to to-space. 3 Now allocate in to-space. Traversing the Object Graph: Most implementations use BFS. Use the to-space as the queue. Updating (Forwarding) Pointers: When an object is moved its new address is stored first in the old copy. from space roots: to space Example: GC from space roots: to space

Copying Collection Example... (A) Algorithm: 1 scan := next := ADDR(to-space) [scan next] hold the BFS queue. Objects above scan point into to-space. Objects between scan and next point into from-space. 2 Copy objects pointed to by the root pointers to to-space. 3 Update the root pointers to point to to-space. from space A B roots from space A B roots to space D B 4 Put each object s new address first in the original. 5 Repeat (recursively) with all the pointers in the new to-space. 1 Update scan to point past the last processed node. 2 Update next to pointe past the last copied node. Continue while scan < next. C D E F C D E F next scan Copying Collection Example... (B) from space A B C roots to space D B next from space A B C roots to space D B E GC Algorithms: Generational Collection D scan D next scan E E F F

Generational Collection Generational Collection... Works best for functional and logic languages (LISP, Prolog, ML,...) because 1 they rarely modify allocated cells 2 newly created objects only point to older objects ((CONS A B) creates a new two-pointer cell with pointers to old objects), 3 new cells are shorter lived than older cells, and old objects are unlikely to die anytime soon. Generational Collection therefore 1 divides the heap into generations, G0 is the youngest, Gn the oldest. 2 allocates new objects in G0. 3 GC s only newer generations. We have to keep track of back pointers (from old generations to new). Functional Language: (cons a (b c)) t1: x new (b c); t2: y new a; t3: return new cons(x, y) A new object (created at time t3) points to older objects. Object Oriented Language: t1: T new Table(0); t2: x new Integer(5); t3: T.insert(x); A new object (created at time t2) is inserted into an older object, which then points to the news object. Generational Collection... Remembered Set: G2 G1 Roots: G0

Generational Collection After GC(G 0 ) Generational Collection... Remembered Set: Roots: G2 G1 G 0 Since old objects (in Gn G1) are rarely changed (to point to new objects) they are unlikely to point into G0. Apply the GC only to the youngest generation (G0), since it is most likely to contain a lot of garbage. Use the stack and globals as roots. There might be some back pointers, pointing from an older generation into G0. Maintain a special set of such pointers, and use them as roots. Occasionally GC older (G1 Gk) generations. Use either mark-and-sweep or copying collection to GC G0. Exam Problem Homework 1 Why is generational collection more appropriate for functional and logic languages (such as LISP and Prolog), than for object-oriented languages (such as Eiffel and Modula-3)? 2 The heap in the figure on the next slide holds 7 objects. All objects have one integer field and one or two pointer fields (black dots). The only roots are the three global variables X, Y, and Z. Free space is shaded. Show the state of To-Space after a copying garbage collection has been performed on From-Space. Note that several answers are possible, depending on the visit strategy (Depth-First or Breadth-First Search) you chose.

Exam Problem I... Exam Problem... From Space 5 Roots: 6 X Y Z 7 8 10 12 13 1 Name five garbage collection algorithms! 2 Describe the Deutsch-Schorr-Waite algorithm! When is it used? Why is it used? How does it work? 3 What are the differences between stop-and-copy, incremental and concurrent garbage collection? When would we prefer one over the other? Readings and References Summary Read the Tiger book: Garbage Collection pp. 257 282 Topics in advanced language implementation, Chapter 4, Andrew Appel, Garbage Collection. Chapter 5, David L. Detlefs, Concurrent Garbage Collection for C++. ISBN 0-262-12151-4. Aho, Hopcroft, Ullman. Data Structures and Algorithms, Chapter 12, Memory Management. Nandakumar Sankaran, A Bibliography on Garbage Collection and Related Topics, ACM SIGPLAN Notices, Volume 29, No. 9, Sep 1994. J. Cohen. Garbage Collection of Linked Data Structures, Computing Surveys, Vol. 13, No. 3, pp. 677 678.