applications - new york university⬛programmers use dynamic memory allocators (such as malloc) to...
TRANSCRIPT
Dynamic Memory Allocation
Computer Systems Organization (Spring 2017)CSCI-UA 201, Section 3
Instructor: Joanna Klukowska
Slides adapted from Randal E. Bryant and David R. O’Hallaron (CMU)
Mohamed Zahran (NYU)
Basic Concepts
2
⬛ Programmers use dynamic memory allocators (such as malloc) to acquire VM at run time.
▪ For data structures whose size is only known at runtime.
⬛ Dynamic memory allocators manage an area of process virtual memory known as the heap. malloc
.text
.data
bss
brk
3
⬛ Allocator maintains heap as collection of variable sized blocks, which are either allocated or free
⬛ Types of allocators
▪ Explicit allocator: application allocates and frees space ▪ E.g., malloc and free in C
▪ Implicit allocator: application allocates, but does not free space▪ E.g. garbage collection in Java, ML, and Lisp
4
malloc
#include <stdlib.h>
void *malloc(size_t size)▪ Successful:
▪ Returns a pointer to a memory block of at least size bytesaligned to an 8-byte (x86) or 16-byte (x86-64) boundary
▪ If size == 0, returns NULL▪ Unsuccessful: returns NULL (0) and sets errno
void free(void *p)▪ Returns the block pointed at by p to the pool of available memory▪ p must come from a previous call to malloc, calloc or realloc
Other functions▪ calloc: Version of malloc that initializes allocated block to zero.
▪ realloc: Changes the size of a previously allocated block.
▪ sbrk: Used internally by allocators to grow or shrink the heap
5
malloc#include <stdio.h>#include <stdlib.h>
void foo(int n) { int i, *p;
/* Allocate a block of n ints */ p = (int *) malloc(n * sizeof(int)); if (p == NULL) { perror("malloc"); exit(0); }
/* Initialize allocated block */ for (i=0; i<n; i++)
p[i] = i;
/* Return allocated block to the heap */ free(p);}
6
⬛ Memory is word addressed.⬛ Words are int-sized.
7
p1 = malloc(4)
p2 = malloc(5)
p3 = malloc(6)
free(p2)
p4 = malloc(2)
8
⬛ Applications▪ Can issue arbitrary sequence of malloc and free requests▪ free request must be to a malloc’d block
⬛ Allocators▪ Can’t control number or size of allocated blocks▪ Must respond immediately to malloc requests
▪ i.e., can’t reorder or buffer requests▪ Must allocate blocks from free memory
▪ i.e., can only place allocated blocks in free memory▪ Must align blocks so they satisfy all alignment requirements
▪ 8-byte (x86) or 16-byte (x86-64) alignment on Linux boxes▪ Can manipulate and modify only free memory▪ Can’t move the allocated blocks once they are malloc’d
▪ i.e., compaction is not allowed
9
⬛ malloc free▪
⬛
▪
⬛
▪▪
▪ malloc free
▪
10
⬛ malloc free▪
⬛
▪ malloc(p) p▪
⬛▪
▪ sbrk
⬛▪
11
▪▪
12
⬛ For a given block, internal fragmentation occurs if payload is smaller than block size
⬛ Caused by ▪ Overhead of maintaining heap data structures▪ Padding for alignment purposes▪ Explicit policy decisions
(e.g., to return a big block to satisfy a small request)▪
⬛ Depends only on the pattern of previous requests▪ Thus, easy to measure
13
⬛
⬛
▪
p1 = malloc(4)
p2 = malloc(5)
p3 = malloc(6)
free(p2)
p4 = malloc(6)
14
⬛
⬛
⬛
⬛
⬛15
▪▪
▪
p0 = malloc(4)
p0
free(p0)
16
⬛ Method 1: Implicit list using length—links all blocks
⬛ Method 2: Explicit list among the free blocks using pointers
⬛ Method 3: Segregated free list▪ Different free lists for different size classes
⬛ Method 4: Blocks sorted by size▪ Can use a balanced binary tree with pointers within each free block, and the length used as a
key
5
5
17
Implicit Free List
18
⬛ For each block we need both size and allocation status▪ Could store this information in two words: wasteful!▪
⬛ Standard trick▪ If blocks are aligned, some low-order address bits are always 0▪ Instead of storing an always-0 bit, use it as a allocated/free flag▪ When reading size word, must mask out this bit
19 20*Assume 8-byte (2 word) align boundary.
⬛ 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
⬛ Next fit:▪ Like first fit, but search list starting where previous search finished▪ Should often be faster than first fit: avoids re-scanning unhelpful blocks▪ Some research suggests that fragmentation is worse
⬛ Best fit:▪ Search the list, choose the best free block: fits, with fewest bytes left over▪ Keeps fragments small—usually improves memory utilization▪ Will typically run slower than first fit
21
▪
addblock(p, 4)
22
▪
▪
free(p) p
malloc(5)
There is enough free space, but the allocator won’t be able to find it (since it sees a block of 4 and block of 2, not a block of 5).
23
▪
▪
free(p) p
24
▪▪▪
25 26
27 28
What do we do, if the next block is free as well? ● Not possible if we always coalesce.
29 30
⬛ Placement policy:▪ First-fit, next-fit, best-fit, etc.▪ Trades off lower throughput for less fragmentation▪ Interesting observation: segregated free lists (next lecture) approximate a best fit placement
policy without having to search entire free list
⬛ Splitting policy:▪ When do we go ahead and split free blocks?▪ How much internal fragmentation are we willing to tolerate?
⬛ Coalescing policy:▪ Immediate coalescing: coalesce each time free is called ▪ Deferred coalescing: try to improve performance of free by deferring coalescing until
needed. Examples:▪ Coalesce as you scan the free list for malloc▪ Coalesce when the amount of external fragmentation reaches some threshold
31
⬛ Implementation: very simple
⬛ Allocate cost: ▪ linear time worst case
⬛ Free cost: ▪ constant time worst case▪ even with coalescing
⬛ Memory usage: ▪ will depend on placement policy▪ First-fit, next-fit or best-fit
⬛ Not used in practice for malloc/free because of linear-time allocation▪ used in many special purpose applications
⬛ However, the concepts of splitting and boundary tag coalescing are general to all allocators
32
Explicit Free List
33
⬛ Method 1: Implicit list using length—links all blocks
⬛ Method 2: Explicit list among the free blocks using pointers
⬛ Method 3: Segregated free list▪ Different free lists for different size classes
⬛ Method 4: Blocks sorted by size▪ Can use a balanced binary tree with pointers within each free block, and the length used as a
key
5
5
34
▪▪
▪▪
35
⬛
⬛
36
= malloc(…)37
⬛
⬛
▪▪▪
⬛
▪
▪▪
38
⬛
free( )
39
⬛
free( )
40
⬛
free( )
41
⬛
free( )
42
⬛
▪▪
▪
▪▪
⬛
▪
43
⬛ Method 1: Implicit list using length—links all blocks
⬛ Method 2: Explicit list among the free blocks using pointers
⬛ Method 3: Segregated free list▪ Different free lists for different size classes
⬛ Method 4: Blocks sorted by size▪ Can use a balanced tree with pointers within each free block, and the length used as a key
5
5
44
Segregated Free List
45
⬛
⬛
⬛
46
⬛
⬛▪▪
▪
▪▪
⬛▪ sbrk()▪▪
47
⬛
▪
⬛
▪▪
▪▪
▪
48
Garbage Collection
49
⬛
⬛
▪
⬛
▪
void foo() { int *p = malloc(128); return; /* p block is now garbage */}
50
⬛
▪
▪
⬛▪
▪▪
int
51
⬛
▪⬛
▪⬛
▪⬛
▪▪
▪
⬛
52
Memory Related Bugs
53
⬛
⬛
⬛
⬛
⬛
⬛
⬛
54
int *p
int *p[13]
int *(p[13])
int **p
int (*p)[13]
int *f()
int (*f)()
int (*(*f())[13])()
int (*(*x[3])())[5]
55
scanf
int val;
...
scanf("%d", val);
56
/* return y = Ax */int *matvec(int **A, int *x) { int *y = malloc(N*sizeof(int)); int i, j;
for (i=0; i<N; i++) for (j=0; j<N; j++) y[i] += A[i][j]*x[j]; return y;}
57
int **p;
p = malloc(N*sizeof(int));
for (i=0; i<N; i++) { p[i] = malloc(M*sizeof(int));}
58
int **p;
p = malloc(N*sizeof(int *));
for (i=0; i<=N; i++) { p[i] = malloc(M*sizeof(int));}
59
char s[8];int i;
gets(s); /* reads “123456789” from stdin */
60
int *search(int *p, int val) { while (*p && *p != val) p += sizeof(int);
return p;}
61
int * heap_delete(int **binheap, int *size) { int *packet; packet = binheap[0]; binheap[0] = binheap[*size - 1]; *size--; heapify(binheap, *size, 0); return(packet);}
62
int *foo () { int val;
return &val;}
63
x = malloc(N*sizeof(int)); <manipulate x>free(x);
y = malloc(M*sizeof(int)); <manipulate y>free(x);
64
x = malloc(N*sizeof(int)); <manipulate x>free(x); ...y = malloc( M*sizeof(int) );for (i=0; i < M; i++) y[i] = x[i]++;
65
foo() { int *x = malloc(N*sizeof(int)); ... return;}
66
struct list { int val; struct list *next;};
foo() { struct list *head = malloc(sizeof(struct list)); head->val = 0; head->next = NULL; <create and manipulate the rest of the list> ... free(head); return;}
67
⬛ gdb▪▪
⬛
▪▪
⬛ valgrind▪▪▪
▪
⬛
▪ setenv MALLOC_CHECK_ 3 (see the manual page for mallopt)
68