Title: Dynamic Memory Allocation
1Dynamic Memory Allocation
2Outline
- Implementation of a simple allocator
- Explicit Free List
- Segregated Free List
- Suggested reading 10.9
3Dynamic Memory Allocation
- Explicit vs. Implicit Memory Allocator
- Explicit application allocates and frees space
- E.g., malloc and free in C
- Implicit application allocates, but does not
free space - E.g. garbage collection in Java, ML or Lisp
4Dynamic Memory Allocation
- Allocation
- In both cases the memory allocator provides an
abstraction of memory as a set of blocks - Doles out free memory blocks to application
5Malloc package
- include ltstdlib.hgt
- void malloc(size_t size)
- if successful
- returns a pointer to a memory block of at least
size bytes, aligned to 8-byte boundary. - if size0, returns NULL
- if unsuccessful returns NULL
- void free(void p)
- returns the block pointed at by p to pool of
available memory - p must come from a previous call to malloc,calloc
or realloc.
6sbrk() Function
- include ltunistd.hgt
- void sbrk(int incr)
- If successful
- It returns the old value of brk
- If unsuccessful
- It returns 1
- It sets errno to ENOMEM
- If incr is zero
- It returns the current value
- incr can be a negative number
7Why Dynamic Memory Allocation
- 1 include "csapp.h"
- 2 define MAXN 15213
- 3
- 4 int arrayMAXN
- 5
- 6 int main()
- 7
- 8 int i, n
- 9
- 10 scanf("d", n)
- 11 if (n gt MAXN)
- 12 app_error("Input file too big")
- 13 for (i 0 i lt n i)
- 14 scanf("d", arrayi)
- 15 exit(0)
- 16
8Why Dynamic Memory Allocation
- 1 include "csapp.h"
- 2
- 3 int main()
- 4
- 5 int array, i, n
- 6
- 7 scanf("d", n)
- 8 array (int )Malloc(n sizeof(int))
- 9 for (i 0 i lt n i)
- 10 scanf("d", arrayi)
- 11 exit(0)
- 12
9Assumptions
- Assumptions made in this lecture
- memory is word addressed (each word can hold a
pointer)
10Allocation examples
11Constraints
- Applications
- Can issue arbitrary sequence of allocation and
free requests - Free requests must correspond to an allocated
block
12Constraints
- Allocators
- Cant control number or size of allocated blocks
- Must respond immediately to all allocation
requests - i.e., cant reorder or buffer requests
- Must allocate blocks from free memory
- i.e., can only place allocated blocks in free
memory
13Constraints
- Allocators
- Must align blocks so they satisfy all alignment
requirements - usually 8 byte alignment
- Can only manipulate and modify free memory
- Cant move the allocated blocks once they are
allocated - i.e., compaction is not allowed
14Goals
- Given some sequence of malloc and free requests
- R0, R1, ..., Rk, ... , Rn-1
- Want to maximize throughput and peak memory
utilization. - These goals are often conflicting
15Performance goals throughput
- Number of completed requests per unit time
- Example
- 5,00 malloc calls and 5,00 free calls in 1
seconds - throughput is 1,000 operations/second.
16Performance goals peak memory utilization
- Given some sequence of malloc and free requests
- R0, R1, ..., Rk, ... , Rn-1
- Def aggregate payload Pk
- malloc(p) results in a block with a payload of p
bytes. - After request Rk has completed, the aggregate
payload Pk is the sum of currently allocated
payloads.
17Performance goals peak memory utilization
- Given some sequence of malloc and free requests
- R0, R1, ..., Rk, ... , Rn-1
- Def current heap size is denoted by Hk
- Note that Hk is monotonically nondecreasing
- Def peak memory utilization
- After k requests, peak memory utilization is
- Uk ( maxiltk Pi ) / Hk
18Fragmentation
- Poor memory utilization caused by fragmentation
- Comes in two forms
- internal fragmentation
- external fragmentation
19Internal Fragmentation
- Internal fragmentation
- For some block, internal fragmentation is the
difference between the block size and the payload
size
20Internal Fragmentation
- Internal fragmentation
- Is caused by overhead of maintaining heap data
structures, padding for alignment purposes, or
explicit policy decisions (e.g., not to split the
block). - Depends only on the pattern of previous requests,
and thus is easy to measure.
21External fragmentation
- Occurs when there is enough aggregate heap
memory, but no single - free block is large enough
22External fragmentation
- External fragmentation depends on
- the pattern of future requests
- and thus is difficult to measure
23Implementation issues
- How do we know how much memory to free just given
a pointer? - How do we keep track of the free blocks?
24Implementation issues
- What do we do with the extra space when
allocating a structure that is smaller than the
free block it is placed in? - How do we pick a block to use for allocation
- many might fit?
- How do we reinsert freed block?
25Knowing how much to free
- Standard method
- keep the length of a structure in the word
preceding the structure - This word is often called the header field or
header - requires an extra word for every allocated
structure
26Knowing how much to free
27Implicit list
- Need to identify whether each block is free or
allocated - Can use extra bit
- Bit can be put in the same word as the size if
block sizes are always multiples of 8 (mask out
low order bit when reading size).
28Implicit list
29Finding a free block
- First fit
- Search list from beginning, choose first free
block that fits - Can take linear time in total number of blocks
(allocated and free) - In practice it can cause splinters at beginning
of list - p start
- while ((p lt end) \\ not passed end
- (p 1) \\ already allocated
- (p lt len) ) \\ too small
30Finding a free block
- Next fit
- Like first-fit, but search list from location of
end of previous search - Research suggests that fragmentation is worse
- Best fit
- Search the list, choose the free block with the
closest size that fits - Keeps fragments small --- usually helps
fragmentation - Will typically run slower than first-fit
31Allocating in a free block
- Allocating in a free block - splitting
- Since allocated space might be smaller than free
space, we might want to split the block
32Freeing a block
- Simplest implementation
- Only need to clear allocated flag
- But can lead to false fragmentation
- There is enough free space, but the allocator
wont be able to find it
33Coalescing
- Join with next and/or previous block if they are
free - Coalescing with next block
- But how do we coalesce with previous block?
34Bidirectional
- Boundary tags Knuth73
- replicate size/allocated word at bottom of free
blocks - Allows us to traverse the list backwards, but
requires extra space - Important and general technique!
35Bidirectional
36Constant time coalescing
37Constant time coalescing (case 1)
m1
1
m1
1
m1
1
m1
1
n
1
n
0
n
1
n
0
m2
1
m2
1
m2
1
m2
1
38Constant time coalescing (case 2)
m1
1
m1
1
m1
1
m1
1
nm2
0
n
1
n
1
m2
0
nm2
0
m2
0
39Constant time coalescing (case 3)
m1
0
nm1
0
m1
0
n
1
n
1
nm1
0
m2
1
m2
1
m2
1
m2
1
40Constant time coalescing (case 4)
m1
0
nm1m2
0
m1
0
n
1
n
1
m2
0
m2
0
nm1m2
0
41Implementing a Simple Allocator
- 1 int mm_init(void)
- 2 void mm_malloc(size_t size)
- 3 void mm_free(void bp)
42Data Structure
43Initialize
- 1 include "csapp.h"
- 2
- 3 / private global variables /
- 4 static void mem_start_brk / points to
first byte of the heap / - 5 static void mem_brk / points to last byte
of the heap / - 6 static void mem_max_addr / max virtual
address for the heap / - 7
- 8 /
- 9 mem_init - initializes the memory system
model - 10 /
- 11 void mem_init(int size)
- 12
- 13 mem_start_brk (void )Malloc(size) /
models available VM / - 14 mem_brk mem_start_brk / heap is
initially empty / - 15 mem_max_addr mem_start_brk size / max
VM address for heap / - 16
- 17
44Initialize
- 18 /
- 19 mem_sbrk - simple model of the the sbrk
function. Extends the heap - 20 by incr bytes and returns the start address
of the new area. In - 21 this model, the heap cannot be shrunk.
- 22 /
- 23 void mem_sbrk(int incr)
- 24
- 25 void old_brk mem_brk
- 26
- 27 if ( (incr lt 0) ((mem_brk incr) gt
mem_max_addr)) - 28 errno ENOMEM
- 29 return (void )-1
- 30
- 31 mem_brk incr
- 32 return old_brk
- 33
45Macros
- 1 / Basic constants and macros /
- 2 define WSIZE 4 / word size (bytes) /
- 3 define DSIZE 8 / doubleword size (bytes) /
- 4 define CHUNKSIZE (1ltlt12) / initial heap size
(bytes) / - 5 define OVERHEAD 8 / overhead of header and
footer (bytes) / - 6
- 7 define MAX(x, y) ((x) gt (y)? (x) (y))
- 8
- 9 / Pack a size and allocated bit into a word
/ - 10 define PACK(size, alloc) ((size) (alloc))
- 11
- 12 / Read and write a word at address p /
- 13 define GET(p) ((size_t )(p))
- 14 define PUT(p, val) ((size_t )(p) (val))
- 15
46Macros
- 16 / Read the size and allocated fields from
address p / - 17 define GET_SIZE(p) (GET(p) 0x7)
- 18 define GET_ALLOC(p) (GET(p) 0x1)
- 19
- 20 / Given block ptr bp, compute address of its
header and footer / - 21 define HDRP(bp) ((void )(bp) - WSIZE)
- 22 define FTRP(bp) ((void )(bp)
GET_SIZE(HDRP(bp)) - DSIZE) - 23
- 24 / Given block ptr bp, compute address of
next and previous blocks / - 25 define NEXT_BLKP(bp) ((void )(bp)
GET_SIZE(HDRP(bp))) - define PREV_BLKP(bp) ((void )(bp) -
GET_SIZE(((void )(bp) - DSIZE))) - size t size GET SIZE(HDRP(NEXT_BLKP(bp)))
47mm_init()
- 1 int mm_init(void)
- 2
- 3 / create the initial empty heap /
- 4 if ((heap_listp mem_sbrk(4WSIZE)) NULL)
- 5 return -1
- 6 PUT(heap_listp, 0) / alignment padding /
- 7 PUT(heap_listpWSIZE, PACK(OVERHEAD, 1)) /
prologue header / - 8 PUT(heap_listpDSIZE, PACK(OVERHEAD, 1)) /
prologue footer / - 9 PUT(heap_listpWSIZEDSIZE, PACK(0, 1)) /
epilogue header / - 10 heap_listp DSIZE
- 11
- 12 / Extend the empty heap with a free block
of CHUNKSIZE bytes / - 13 if (extend_heap(CHUNKSIZE/WSIZE) NULL)
- 14 return -1
- 15 return 0
- 16
48mm_init()
- 1 static void extend_heap(size_t words)
- 2
- 3 char bp
- 4 size_t size
- 5
- 6 / Allocate an even number of words to
maintain alignment / - 7 size (words 2) ? (words1) WSIZE
words WSIZE - 8 if ((int)(bp mem_sbrk(size)) lt 0)
- 9 return NULL
- 10
- 11 / Initialize free block header/footer and
the epilogue header / - 12 PUT(HDRP(bp), PACK(size, 0)) / free
block header / - 13 PUT(FTRP(bp), PACK(size, 0)) / free
block footer / - 14 PUT(HDRP(NEXT_BLKP(bp)), PACK(0, 1)) /
new epilogue header / - 15
- 16 / Coalesce if the previous block was free
/ - 17 return coalesce(bp)
- 18
49mm_free()
- 1 void mm_free(void bp)
- 2
- 3 size_t size GET_SIZE(HDRP(bp))
- 4
- 5 PUT(HDRP(bp), PACK(size, 0))
- 6 PUT(FTRP(bp), PACK(size, 0))
- 7 coalesce(bp)
- 8
- 9
50mm_free()
- 10 static void coalesce(void bp)
- 11
- 12 size_t prev_alloc GET_ALLOC(FTRP(PREV_BLKP(
bp))) - 13 size_t next_alloc GET_ALLOC(HDRP(NEXT_BLKP(
bp))) - 14 size_t size GET_SIZE(HDRP(bp))
- 15
- 16 if (prev_alloc next_alloc) / Case 1 /
- 17 return bp
- 18
- 19
- 20 else if (prev_alloc !next_alloc) /
Case 2 / - 21 size GET_SIZE(HDRP(NEXT_BLKP(bp)))
- 22 PUT(HDRP(bp), PACK(size, 0))
- 23 PUT(FTRP(bp), PACK(size,0))
- 24 return(bp)
- 25
- 26
51mm_free()
- 27 else if (!prev_alloc next_alloc) /
Case 3 / - 28 size GET_SIZE(HDRP(PREV_BLKP(bp)))
- 29 PUT(FTRP(bp), PACK(size, 0))
- 30 PUT(HDRP(PREV_BLKP(bp)), PACK(size, 0))
- 31 return(PREV_BLKP(bp))
- 32
- 33
- 34 else / Case 4 /
- 35 size GET_SIZE(HDRP(PREV_BLKP(bp)))
- 36 GET_SIZE(FTRP(NEXT_BLKP(bp)))
- 37 PUT(HDRP(PREV_BLKP(bp)), PACK(size, 0))
- 38 PUT(FTRP(NEXT_BLKP(bp)), PACK(size, 0))
- 39 return(PREV_BLKP(bp))
- 40
- 41
52mm_malloc()
- 1 void mm_malloc (size_t size)
- 2
- 3 size_t asize / adjusted block size /
- 4 size_t extendsize / amount to extend heap
if no fit / - 5 char bp
- 6
- 7 / Ignore spurious requests /
- 8 if (size lt 0)
- 9 return NULL
- 10
- 11 / Adjust block size to include overhead and
alignment reqs. / - 12 if (size lt DSIZE)
- 13 asize DSIZE OVERHEAD
- 14 else
- 15 asize DSIZE ((size (OVERHEAD)
(DSIZE-1)) / DSIZE) - 16
53mm_malloc()
- 17 / Search the free list for a fit /
- 18 if ((bp find_fit(asize)) ! NULL)
- 19 place (bp, asize)
- 20 return bp
- 21
- 22
- 23 / No fit found. Get more memory and place
the block / - 24 extendsize MAX (asize, CHUNKSIZE)
- 25 if ((bp extend_heap (extendsize/WSIZE))
NULL) - 26 return NULL
- 27 place (bp, asize)
- 28 return bp
- 29
54mm_alloc()
- static void find_fit(size_t asize)
-
- void bp
-
- / first fit search /
- for (bp heap_listp GET_SIZE(HDRP(bp)) gt 0
bp NEXT_BLKP(bp) ) - if (!GET_ALLOC(HDRP(bp))
(asizeltGET_SIZE(HDRP(bp)))) - return bp
-
-
- return NULL /no fit /
-
55mm_alloc()
- static void place(void bp, size_t asize)
-
- size_t csize GET_SIZE(HDRP(bp))
-
- if ( (csize asize) gt (DSIZE OVERHEAD) )
- PUT(HDRP(bp), PACK(asize, 1))
- PUT(FTRP(bp), PACK(asize, 1))
- bp NEXT_BLKP(bp)
- PUT(HDRP(bp), PACK(csize-asize, 0)
- PUT(FTRP(bp), PACK(csize-asize, 0)
- else
- PUT(HDRP(bp), PACK(csize, 1)
- PUT(FTRP(bp), PACK(csize, 1)
-
56Explicit free lists
- Explicit list among the free blocks using
pointers within the free blocks - Use data space for link pointers
- Typically doubly linked
- Still need boundary tags for coalescing
- It is important to realize that links are not
necessarily in the same order as the blocks
57Explicit free lists
58Freeing with explicit free lists
- Where to put the newly freed block in the free
list - LIFO (last-in-first-out) policy
- insert freed block at the beginning of the free
list - pro simple and constant time
- con studies suggest fragmentation is worse than
address ordered.
59Freeing with explicit free lists
- Where to put the newly freed block in the free
list - Address-ordered policy
- insert freed blocks so that free list blocks are
always in address order - i.e. addr(pred) lt addr(curr) lt addr(succ)
- con requires search
- pro studies suggest fragmentation is better
than LIFO
60Segregated Storage
- Each size class has its own collection of
blocks - Often have separate collection for every small
size (2,3,4,) - For larger sizes typically have a collection for
each power of 2
61Segregated Storage
62Simple segregated storage
- Separate heap and free list for each size class
- No splitting
- To allocate a block of size n
- if free list for size n is not empty,
- allocate first block on list (note, list can be
implicit or explicit) - if free list is empty,
- get a new page
- create new free list from all blocks in page
- allocate first block on list
- constant time
63Simple segregated storage
- To free a block
- Add to free list
- If page is empty, return the page for use by
another size (optional) - Tradeoffs
- fast, but can fragment badly
64Segregated fits
- Array of free lists, each one for some size class
65Segregated fits
- To allocate a block of size n
- search appropriate free list for block of size m
gt n - if an appropriate block is found
- split block and place fragment on appropriate
list (optional) - if no block is found, try next larger class
- repeat until block is found
- if no blocks is found in all classes, try more
heap memory
66Segregated fits
- To free a block
- coalesce and place on appropriate list (optional)
- Tradeoffs
- faster search than sequential fits (i.e., log
time for power of two size classes) - controls fragmentation of simple segregated
storage - coalescing can increase search times
- deferred coalescing can help
67Buddy Systems
- A special case of segregated fits
- Each size is power of 2
- Initialize
- A heap of size 2m
68Buddy Systems
- Allocate
- Roundup to power of 2 such as 2k
- Find a free block of size 2j (k ? j ? m)
- Split the block in half until jk
- Each remaining half block (buddy) is placed on
the appreciate free list - Free
- Continue coalescing with the free buddies