MC logo
Memory Management
[^] Chapter Outlines
[Ch. 1: Overview and History] [Syntax] [Names and Scope] [Types and Type Systems] [Semantics] [Functions] [Memory Management] [Imperitive Programs and Functional Abstraction] [Modular and Class Abstraction] [Functional Programming] [Logic Programming]
[Buddy System Example] [Reference Counting] [Trashy Heap]
<<Functions Imperitive Programs and Functional Abstraction>>
  1. Memory layout.
    1. Static area is allocated at compile time.
    2. Stack holds function activation and grows down.
    3. Heap holds dynamically-allocated areas and grows up.
  2. Variable-sized arrays.
    1. May be allocated on stack or heap.
    2. When on the heap, a dope vector may exist on the stack with dimensions and a pointer.
  3. Heap management.
    1. Simple free list.
    2. Buddy system.
      1. Dividing memory
      2. Powers-of-two free lists.
  4. Garbage Collection
    1. Let the programmer worry about it.
      1. Programmer must explicitly free memory when finished.
      2. Easy to forget.
      3. Particularly a problem when exceptions are caught.
            allocate a bunch of memory
            do stuff that might throw exceptions
            free the memory
            Now you have a bunch of garbage.
    2. C++ auto_ptr
      1. Deletes the object when the pointer is destroyed.
      2. Not a general solution.
      3. Helpful for exceptions.
    3. Reference counting.
      1. Each allocated block keeps a count of how many pointers there are to it.
      2. Counts are updated whenever pointers are created or destroyed.
      3. If the count reaches zero, the block is freed.
      4. Fails for circular structures.
    4. Mark-and-sweep.
      1. Pointers on the stack are called roots.
      2. When you run out of memory:
        1. Recursively find and mark each block reachable from some root.
        2. Un-marked parts are garbage. Delete them.
      3. Marking is the hard part. The more you do, the less you get.
      4. Mark This.
    5. Copy collection.
      1. Divide memory into two equal parts. Allocate from one; other stays idle.
      2. When you run out of memory (from the active half):
        1. Recursively find each block reachable from some root, and copy it to the inactive half.
        2. Keep track of which blocks you've moved, and redirect all existing pointers to the new copies.
        3. Garbage naturally remains uncopied.
        4. Swap active sides.
        5. Copy this.
      3. Avoids extra space for counts or marks at the cost of half of memory.
      4. No free list, so no free list search needed for new allocations.
<<Functions Imperitive Programs and Functional Abstraction>>