COMP 3355 Notes – Dynamic Memory Allocation
Reading: section 11.5
Plan
Overview
Run-Time Environments
Heap Management
Storage Classes
Overview
Recall:
Static allocation of memory is when memory reservation requirements are
determined at compile- (or assemble-) time.
Dynamic allocation of memory is when memory is acquired and released
throughout run-time, based on current need.
E.g. a statically allocated, singly linked list in asm:
data equ 0 ; node type for a list of words
next equ 2
NODE_SIZE equ 6
NULL equ 0 ; why zero for the NULL pointer?
head: dc.l node1
node1: dc.w 1
dc.l node2
... ; must the nodes be contiguous?
node2: dc.w 2 ; must the declaration order be fixed?
dc.l NULL
In order for data structures to grow (and shrink) at run-time, dynamic allocation of
memory must be possible.
Page 1 of 6
Run-Time Environments
A high-level language provides a run-time environment. It provides:
initial program set up (i.e. before calling a “main” function)
final program tear down (i.e. after “main” returns)
a set of callable library functions
The run-time environment is responsible for maintaining a pool of available memory:
the heap, plus routines for allocating and deallocating blocks of memory.
E.g. C provides the standard library functions:
void *malloc(size_t); allocates a block from the heap
void free(void *) returns a block to the heap
E.g. C++ provides the operators:
new calls malloc
delete calls free
Asm programs have no default high-level run-time environment! They must create and
manage their own heaps (or link to an existing run-time environment such as libc).
Heap Management
Heap space must be set aside at the beginning of the program.
E.g.
heap: ds.b HEAP_SIZE
or, if only one type of node will ever be allocated:
heap: ds.b NUM_NODES*NODE_SIZE
Page 2 of 6
There are numerous heap management strategies. We consider only a few, briefly:
1. FIXED SIZE BLOCKS
a) one-time allocation:
allocation = if heap empty
then
set address = NULL
otherwise
set address = “next available”
increment “next available” pointer by block size
return address
deallocation = n/a
Discuss: pros & cons
b) reusable nodes:
maintain a free list of blocks: each free block points at next free block in heap
Diagram: draw initial free list (all free blocks are initially contiguous)
allocation = set address = free list head pointer
if address ≠ NULL then remove head block from free list
return address
deallocation = insert block back into free list at head
Exercise: given the node type from above and:
freep: dc.l heap
heap: ds.b NUM_NODES*NODE_SIZE
in asm, write:
void *malloc();
void free(void *);
void init_heap();
Page 3 of 6
2. VARIABLE SIZE BLOCKS
a) use method (1b) above, but with segregated free lists (“bins”) for each block
size
b) block subdivision (overview):
Begin with one huge block in the free list.
During allocation, subdivide when necessary.
Can use a first fit strategy: use 1st block which has size ≥ requested.
Can use a best fit strategy: search for smallest block which can satisfy the
request.
If no “big enough” block is found, allocation request fails (or can request
another large block of memory from the O/S, and add it to free list).
For deallocation, re-insert into free list
During deallocation, coalesce with free neighbours when possible.
Diagram: picture of one free list node (w/ pointer, size & memory)
Diagram: picture of entire free list (w/ some blocks in use, others free)
Problem: fragmentation is the gradual loss of useful space. There are 2 kinds:
1. internal fragmentation: space is lost within an allocated block (because of
minimum block sizes)
2. external fragmentation: space is lost between allocated blocks
Diagram: an externally fragmented heap
Excessive fragmentation may result in a failed allocation request, even if enough total
memory is available!
Some solutions:
implement compaction: a periodic defragmentation of the heap
maintain multiple heaps, each for a different block size (e.g. glibc under
Linux)
Page 4 of 6
Common dynamic allocation errors:
not checking “out of memory” condition
memory leaks
using memory once freed
freeing memory twice
overflowing an allocated block
Typically, when allocating memory dynamically, the request for more space is
ultimately made to the O/S.
Memory map for a Linux process:
HIGH MEMORY ?
stack
stack top
(unallocated space)
heap “break point”
heap
code & static data
LOW MEMORY ?
Requesting memory from the O/S is “expensive”.
Heap managers make large, infrequent requests from the O/S and then subdivide the
obtained block.
E.g. in Unix/Linux, C’s malloc library function makes infrequent calls to the brk
system call, which raises the “break point”.
Page 5 of 6
Storage Classes
The storage class of a variable refers to the region from where it is allocated. This also
relates to when it is allocated and deallocated (“lifetime”).
In C/C++ -like languages, the 4 typical storage classes are:
1. static
2. dynamic (“heap dynamic”) run-time allocation from heap
3. automatic (“stack dynamic”) run-time allocation on stack
4. register
This is distinct from variable “scope”, which refers to identifier visibility (e.g. global vs.
local variables).
Page 6 of 6