11 Memallocation
11 Memallocation
Computer
system:
Top of heap
(brk ptr)
Heap (via malloc)
0
Autumn 2013 Memory Allocation 3
University of Washington
Malloc Example
void foo(int n, int m) {
int i, *p;
Assumptions
¢ Memory is word addressed (each word can hold a pointer)
§ block size is a multiple of words
p2 = malloc(20)
p3 = malloc(12)
free(p2)
p4 = malloc(8)
Constraints
¢ Applications
§ Can issue arbitrary sequence of malloc() and free() requests
§ free() requests must be made only for a previously 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., blocks can’t overlap, why not?
§ Must align blocks so they satisfy all alignment requirements
§ 8 byte alignment for GNU malloc (libc malloc) on Linux
§ Can’t move the allocated blocks once they are malloc()’d
§ i.e., compaction is not allowed. Why not?
¢ Throughput:
§ Number of completed requests per unit time
§ Example:
§ 5,000 malloc() calls and 5,000 free() calls in 10 seconds
§ Throughput is 1,000 operations/second
Fragmentation
¢ Poor memory utilization is caused by fragmentation.
¢ Sections of memory are not used to store anything useful, but
cannot be allocated.
¢ internal fragmentation
¢ external fragmentation
Internal Fragmentation
¢ For a given block, internal fragmentation occurs if payload is smaller than
block size
block
Internal Internal
payload
fragmentation fragmentation
¢ Caused by
§ overhead of maintaining heap data structures (inside block, outside payload)
§ padding for alignment purposes
§ explicit policy decisions (e.g., to return a big block to satisfy a small request)
why would anyone do that?
p1 = malloc(16)
p2 = malloc(20)
p3 = malloc(24)
free(p2)
Implementation Issues
¢ How do we know how much memory to free given just a
pointer?
p0
p0 = malloc(16) 20
free(p0)
20 16 24 8
20 16 24 8
Start of heap
Free word
8|0 16|1 32|0 16|1 0|1 Allocated word
Allocated word
unused
¢ 8-byte alignment
§ May require initial unused word
§ Causes some internal fragmentation
¢ Special one-word marker (0|1) marks end of list
§ zero size is distinguishable from all real sizes
Autumn 2013 Memory Allocation 19
University of Washington
§ Can take time linear 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 helps fragmentation
Autumn 2013
§ Will typically run slower than first-fit
Memory Allocation 20
University of Washington
8 24 8
b
malloc(12) à split(b, 16)
8 16 8 8
assume ptr points to word and has unscaled pointer arithmetic
void split(ptr b, int bytes) { // bytes = desired block
size
int newsize = ((bytes + 7) >> 3) << 3;// round up to multiple of 8
int oldsize = *b; // why not mask out low bit?
*b = newsize; // initially unallocated
if (newsize < oldsize)
*(b+newsize) = oldsize - newsize; // set length in remaining
} 2013
Autumn Memory Allocation // part of block (UNSCALED 21
University of Washington
8 16 8 8
free(p) p
8 16 8 8
malloc(20) Oops!
There is enough free space, but the allocator won’t be able to find it
16 16 8 8
logically
p
free(p) gone
16 24 8 8
16 16 16 16 24 24 16 16
Header size a
a = 1: allocated block
Format of a = 0: free block
allocated and payload and
size: total block size
free blocks padding
payload: application data
Boundary tag size a (allocated blocks only)
(footer)
m1 1 m1 1 m1 1 m1 1
n 1 n 0 n 1 n+m2 0
n 1 n 0 n 1
m2 1 m2 1 m2 0
m2 1 m2 1 m2 0 n+m2 0
m1 0 n+m1 0 m1 0 n+m1+m2 0
m1 0 m1 0
n 1 n 1
n 1 n+m1 0 n 1
m2 1 m2 1 m2 0
m2 1 m2 1 m2 0 n+m1+m2 0
Autumn 2013 Memory Allocation 26
University of Washington
20 16 24 8
¢ Method 2: Explicit free list among the free blocks using pointers
20 16 24 8
size a size a
next
size a size a
(same as implicit free list)
A B C
¢ Physically?
A B C
= malloc(…)
Autumn 2013 Memory Allocation 33
University of Washington
§ Address-ordered policy
§ Insert freed blocks so that free list blocks are always in address
order:
addr(prev) < addr(curr) < addr(next)
§ Con: requires linear-time search when blocks are freed
§ Pro: studies suggest fragmentation is lower than LIFO
¢ Cache effects?
Autumn 2013 Memory Allocation 35
University of Washington
Root
After
Root
Root
Root
Root
Root
Root
Root
size a size a
next
size a size a
20 16 24 8
20 16 24 8
16
24-32
40-inf
Seglist Allocator
¢ Given an array of free lists, each one for some size class
¢ If no block is found:
§ Request additional heap memory from OS (using sbrk())
§ Allocate block of n bytes from this new memory
§ Place remainder as a single free block in largest size class
Seglist Allocator
¢ To free a block:
§ Coalesce and place on appropriate list (optional)
¢ 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
Autumn 2013 Memory Allocation 46
University of Washington
Wouldn’t it be nice…
¢ If we never had to free memory?
¢ Do you free objects in Java?
Garbage Collection
¢ How does the memory allocator know when memory can be
freed?
§ In general, we cannot know what is going to be used in the future since it
depends on conditionals (halting problem, etc.)
Garbage Collection
¢ How does the memory allocator know when memory can be
freed?
§ In general, we cannot know what is going to be used in the future since it
depends on conditionals (halting problem, etc.)
§ But, we can tell that certain blocks cannot be used if there are no
pointers to them
Classical GC Algorithms
¢ Mark-and-sweep collection (McCarthy, 1960)
§ Does not move blocks (unless you also “compact”)
¢ Reference counting (Collins, 1960)
§ Does not move blocks (not discussed)
¢ Copying collection (Minsky, 1963)
§ Moves blocks (not discussed)
¢ Generational Collectors (Lieberman and Hewitt, 1983)
§ Most allocations become garbage very soon, so
focus reclamation work on zones of memory recently allocated.
¢ For more information:
§ Jones, Hosking, and Moss, The Garbage Collection Handbook: The Art
of Automatic Memory Management, CRC Press, 2012.
§ Jones and Lin, Garbage Collection: Algorithms for Automatic Dynamic
Memory, John Wiley & Sons, 1996.
Memory as a Graph
¢ We view memory as a directed graph
§ Each allocated heap block is a node in the graph
§ Each pointer is an edge in the graph
§ Locations not in the heap that contain pointers into the heap are called
root nodes (e.g. registers, locations on the stack, global variables)
Root nodes
Not-reachable
(garbage)
A node (block) is reachable if there is a path from any root to that node
Non-reachable nodes are garbage (cannot be needed by the application)
Autumn 2013 Memory Allocation 53
University of Washington
Before mark
Mark
Mark using depth-first traversal of the memory graph
ptr mark(ptr p) { // p: some word in a heap block
if (!is_ptr(p)) return; // do nothing if not pointer
if (markBitSet(p)) return; // check if already marked
setMarkBit(p); // set the mark bit
for (i=0; i < length(p); i++) // recursively call mark on
mark(p[i]); // all words in the block
return;
}
root
Before mark
Sweep
int val;
...
scanf(“%d”, val);
int val;
...
scanf(“%d”, val);
/* return y = Ax */
int *matvec(int **A, int *x) {
int *y = (int *)malloc( N * sizeof(int) );
int i, j;
Overwriting Memory
¢ Allocating the (possibly) wrong sized object
int **p;
Overwriting Memory
¢ Off-by-one error
int **p;
Overwriting Memory
¢ Not checking the max string size
char s[8];
int i;
Overwriting Memory
¢ Misunderstanding pointer arithmetic
return p;
}
Overwriting Memory
¢ Referencing a pointer instead of the object it points to
int *foo () {
int val;
return &val;
}
foo() {
int *x = (int *)malloc(N*sizeof(int));
...
return;
}
struct list {
int val;
struct list *next;
};
foo() {
struct list *head =
(struct list *)malloc( sizeof(struct list) );
head->val = 0;
head->next = NULL;
<create and manipulate the rest of the list>
...
free(head);
return;
}
Autumn 2013 Memory Allocation 73
University of Washington
Root nodes
Not-reachable
(garbage)