324 Lecture Week 13 - Winter 2006 ================================= Procedural Language Design Issues ================================= Procedural Language Design I & II: http://www.cs.toronto.edu/~sheila/324/f05/slides/index.html Exception Handling ================== Recall that many functions are partial -- they are only defined for a subset of the function's domain type. Other values in the domain type may be treated as exceptions. (E.g., division by zero) Exceptions are a control construct. They provide a structured form of jump to exit a construct such as a function invocation or a block. Why do we need exceptions in a strongly typed language? - only checks types of parameters, not their values - In languages w/o exception handling, when an exception occurs, control goes to the OS and the program is terminated, or special code must be written to handle exceptions (e.g., pass special parameter or use return value of procedure to indicate status of program, etc.) - In contrast, with exception handling, programs can "fix the problem" and continue, if desirable. Exceptions & Scoping -------------------- Exceptions are handled according to dynamic scoping. Most other things are static scoping. General dynamic scoping rule: - Jump to most recently established handler on run-time stack Dynamic scoping is not an accident: - User knows how to handler error - Author of library function does not Run-time Storage Management (garbage collection) =========================== Stack - contains activation records, local variables, return addresses Heap - contains dynamically allocated data How is heap managed? - single size for all cells, or - variable size segments In LISP/Scheme, cells are often created and soon thrown away, don't want the user to have to deal with memory management Garbage - allocated memory no longer referencable (since all pointers/references are destroyed) How to clean up garbage (and avoid memory leaks)? When to clean up garbage? Two main methods: - reference counters - garbage collection Reference counters: - reclamation is incremental, done when inaccessible cells are created - eager approach - a counter is maintained in every cell, storing the number of references to that cell - in decrement operation, a check is made whether counter is zero - if so, cell is deallocated - expensive in space if cells are small - time required every time a pointer is changed - eg. in LISP/Scheme, almost every action involves pointer changes - if cells are linked circularly, each cell in the cycle will always have at least one reference Garbage collection: - reclamation occurs when the list of available space becomes empty - lazy approach - cells allocated and pointers disconnected without extra checks - garbage accumulates - when no space left, garbage is collected - all cells have an extra bit to aid in garbage collection - three phases in garbage collection: - indicators set in all cells, assume all is garbage - trace every active pointer in the program and mark reachable cells as not being garbage (difficult!) - all cells still marked as garbage are deallocated. - biggest problem: "works the worst when needed the most" - when program uses most cells in heap, GC takes a long time, occurs often - mitigated by modern computers having large memories, virtual memory Variable size cells: - harder to mark all cells as garbage, as don't know sizes or where they are - in structures, how do we find all pointers to other cells? - overhead of maintaining list of available space - blocks might be too small to fit a new large block, need compaction either to merge adjacent free cells (easy) or move allocated memory to new locations (hard)