New Heap Management algorithm (Coursera version)

New Heap Management algorithm (Coursera version)

Coursera part 2 introduces a slight variation of the Heap Management algorithm presented in the book.

The significant changes are

The size field in the segment headers has changed to be the size of the segment's data block instead of the size of the segment itself.

Segments are always split into two segments when an allocated segment is returned from Memory.alloc().

The returned block contains a complete header. (In the book's algorithm, allocated segments have size as a single-word header.)

Also note the trivial change that the order of the link and size fields has been swapped.

Before alloc(5)

freeList

→

next

→

next

→

null

2

8

3

After alloc(5)

freeList

→

next

→

next

→

null

2

1

3

null

*

5

returned block

→

* See Allocated block header section, below.

Figure 1: New Heap Management algorithm

Memory.alloc() changes

The search loop in Memory.alloc() remains the same—using either first-fit or best-fit, find a segment on the free list whose size is greater than or equal to the requested block size.

In the Book algorithm, once a large enough segment is found, the segment is either used in its entirety, or it is split into two segments. If the entire segment is used, the segment must be removed from the free list. This is a non-trivial operation because the search loop must keep track of two pointers during the linked-list search so that the segment that links to the segment to be removed can have its next pointer updated.

The Coursera algorithm vastly simplifies this by always spliting the found segment and using the newly created segment for the allocated block. The found segment is reduced in size but is never removed from the free list. Another useful effect of always splitting segments for allocation is that the free list will never be empty; the freeList pointer will never be null.

Memory.deAlloc() changes

Memory.deAlloc() is simplified because the size field is already in the correct location and has the correct value. The deallocated segment just needs to be returned to the free list.

Allocated block header

The Coursera algorithm sets the next pointer in the block header to null. An improvement would be to set it to a signature, a known value that is neither null nor a legal pointer value. This will allow dealloc() to check if the block being deallocated is an allocated block. (Double deallocation is a common programming error.)

The simplest signature scheme is to set the next field to an easily recognizable value like -31416.

An alternative is to set the next field to a value derived from the block size. This would help prevent allocated blocks that had their header overwritten from being placed on the free list and corrupting the heap. Setting the block size to not(block size) will form a suitable value that is an illegal address.

Fragmentation

The Coursera algorithm is more susceptible to fragmentation than the Book algorithm because it always splits the heap segment that is used for a block allocation. This means that a block that is deallocated will be too small to satisfy a request for another block of the same size. A program that is repeatedly creating and disposing the same object will inevitably run out of memory.

Defragmentation

Defragmentation is not required by the course, but may be necessary if you want to run your game using your OS. Here is a fairly easy way to do defragmentation in Memory.deAlloc().

Insert the deallocated segment into the free list in ascending segment address order.

After insertion, check if either or both the preceding segment or next segment is contiguous with the newly inserted segment; if so, combine the segments.

Another useful property of the Coursera Memory.alloc() algorithm is that because segments are always split and the unallocated portion remains on the free list, the initial segment—the segment at 2048—will always be present on the free list. By maintaining the free list in address order, the first free segment will always be the 2048 segment and there will be no need for a special case to handle insertion at the head of the list.

To find the highest addressed segment that is less than the segment being deallocated, search the list for the first segment that has a next pointer that null or is greater that the deallocated segment's address.

Results

I wrote a test program that allocates 20 blocks randomly sized 200..600 words. It then runs 10,000 passes randomly deallocating 5 of the blocks then reallocating 5 new blocks. Increasing the block size by 25% (to 250..750) causes an allocation failure.[1]