CSCI 431: Storage management

Static storage management

Stack-Based storage management

Figure 5.5  and  5.6

Local data is stored in an area called an activation record (also called a stack frame).

Address data is a two step process:
1. Get a pointer to the relevant activation record containing the declarations.
2. Find the offset in that activation record for the data item.

IMPORTANT:
1. The activation record pointer is determined at during program execution. It occurs frequently, so it should be an efficient calculation.
2. The offset within an activation record is fixed and determined during compilation. It should require no - or minimal - calculations.

Heap Storage

In functional languages, we cannot use stack-based storage for many data structures, for example, functions that are the return values of other functions. As a result, run-time data stuctures must be allocated from the heap.

A heap is a block of storage within which pieces are allocated and freed in some relatively unstructured manner.

The need for heap storage arises when a language permits storage to be allocated and freed at arbitrary points during program execution.

The heap is the major storage area for ML, LISP and Prolog is a heap. Most object-oriented languages also rely on heap allocated memory for objects.

Because it is often not clear when memory can be safely freed, such languages usually rely on an automatic mechanism for recycling memory.

There is no single heap storage management technique, but rather a collection of techniques for handling various aspects of managing this memory.

Programmer controled storage management

Dynamic allocation and stacks are generally incompatible.

Problems caused by explicit return of the free-space by the programmer

Dangling reference (a pointer to storage that has been freed):
allocate(x);
y = x;
free(x);
==> y still points to allocated item

Garbage (inaccessible storage):
allocate(x);
allocate(x);
==> first allocation to x now lost.

Memory fragmentation:
allocate(a);
allocate(x);
allocate(y);
free(a);
allocate(z);
free(y);
allocate(b);
==> No contiguous space for b

Recovery

The simplest recovery technique is that of explicit return -- when an element that has been in use becomes available for reuse, it must be explicitly identified as free and returned to the free-space list.

Many problems can result from dangling references and garbage.

Alternative recovery techniques:  garbage collection and reference counts

First assume memory is allocateced in fixed size blocks with each block being size k.

Two simple algorithms are as follows.

Algorithm 1: Garbage collection with the two pass mark-sweep algorithm:

1. Keep a linked list (free list) of memory blocks available to be allocated.
2. Allocate memory blocks on demand.
3. Ignore free commands.
4. When out of space, perform garbage collection:
Pass 1: Mark every memory block still allocated.
Pass 2: Every unmarked memory blocks is added to the free list of available blocks.

The problem is how do you know if a memory block is still allocated:

  1. there is a pointer to it from outside the heap
  2. there is a pointer to it from an active heap element

Easy if regular use of pointers (Like in LISP)

  1. All elements must be reachable by a chain of pointers which begins outside the heap
  2. Have to be able to know where all pointers are - both inside the heap and outside

Error conditions:


Algorithm 2: Reference Counts (eager method of storage reclamation)

1. Associate a reference counter field, initially 0, with every allocated memory block.
2. Each time a pointer is set to an memory block, up the reference counter by 1.
3. Each time a pointer no longer points to an memory block, decrease the reference counter by 1.
4. If reference counter ever returns to 0, then free memory block.

Error conditions:
Dangling reference - Cannot occur. Reference count is 0 only when nothing points to it.
Fragmentation - Cannot occur. All memory blocks are fixed size.
Inaccessible storage - Can still occur, but not easily. ...

Heap Storage Management - Variable Sized Elements

Memory operations