Memory Management

CMPU 334 – Operating Systems Jason Waterman Memory API: malloc()

#include

void* malloc(size_t size) • Allocate a memory region on the heap • Argument • size_t size : size of the memory block (in ) • size_t is an unsigned integer type capable of holding the size of any valid memory request • Often used with sizeof(type)operator which returns the size of the argument • Return • Success: a void type pointer to the memory block allocated by malloc • Fail: a

9/14/21 CMPU 334 -- Operating Systems 2 Memory API: sizeof()

• Good coding style to use sizeof in malloc instead of requesting the number of bytes directly • Two types of results of sizeof with variables • The actual size of ‘x’ is known at run-time

int *x = malloc(10 * sizeof(int)); printf(“%d\n”, sizeof(x));

8 • The actual size of ‘x’ is known at compile-time

int x[10]; printf(“%d\n”, sizeof(x));

40

9/14/21 CMPU 334 -- Operating Systems 3 Memory API: free()

#include

void free(void* ptr) • Free a memory region allocated by a call to malloc • Argument • void *ptr : a pointer to a memory block allocated with malloc • Returns • none

9/14/21 CMPU 334 -- Operating Systems 4 Memory Allocating

2KB

heap

(free) stack int *pi; // local variable

pi 16KB Address Space

2KB points to allocated 2KB + 4 allocated 2KB + 8 allocated 2KB + 12 allocated pi = (int *)malloc(sizeof(int)* 4);

(free)

2KB pi 16KB Address Space

9/14/21 CMPU 334 -- Operating Systems 5 Memory Freeing

2KB freed 2KB + 4 freed 2KB + 8 freed 2KB + 12 free(pi); freed

(free)

pi 16KB Address Space

2KB

heap

(free) stack

2KB(invalid) pi 16KB Address Space 9/14/21 CMPU 334 -- Operating Systems 6 Forgetting To Allocate Memory

• Incorrect code char *src = “hello”; // string constant char *dst; //unallocated strcpy(dst, src); //segfault and die

hello\0

heap strcpy(dst, src); (free) unallocated stack

*dst *src Address Space

9/14/21 CMPU 334 -- Operating Systems 7 Forgetting To Allocate Memory (Cont.)

• Correct code char *src = “hello”; //character string constant char *dst (char *)malloc(strlen(src) + 1 ); // allocated strcpy(dst, src); //work properly

hello\0 hello\0

allocated hello\0

strcpy(dst, src); heap heap (free) (free) stack stack

*dst *dst *src *src Address Space Address Space

9/14/21 CMPU 334 -- Operating Systems 8 Not Allocating Enough Memory

• Incorrect code, but “works” properly char *src = “hello”; //character string constant char *dst (char *)malloc(strlen(src)); // too small strcpy(dst, src); //works “properly”

h e strlen 6 bytes l l o \0

‘\0’ is omitted 5 bytes hello\0

strcpy(dst, src); heap (free) stack

*dst *src Address Space 9/14/21 CMPU 334 -- Operating Systems 9 Forgetting to Initialize

• Encounter an uninitialized read

int *x = (int *)malloc(sizeof(int)); // allocated printf(“*x = %d\n”, *x); // uninitialized memory access

allocated value used before with value used (free) before

heap heap

(free) (free)

stack stack

x x Address Space Address Space

9/14/21 CMPU 334 -- Operating Systems 10 Memory Leak

• A program runs out of memory and eventually dies unused : unused, but not freed

allocated unused unused

allocated unused

heap heapunused heap (free) allocated (free) stack (free) stack *d * *b *b *a *a *a Address Space Address Space Address Space

run out of memory

9/14/21 CMPU 334 -- Operating Systems 11 Dangling Pointer

• Freeing memory before it is finished being used

free() *b *b unreachable *a *a

dangling pointer

2KB 2KB 3KB 3KB 3KB 3KB 4KB freed free(b) 4KB 4KB NULL NULL Heap Heap

(free) (free)

Stack Stack *b 3KB *b 3KB *a 2KB *a 2KB Address Space Address Space 9/14/21 CMPU 334 -- Operating Systems 12 Double Free

• Free memory that was freed already int *x = (int *)malloc(sizeof(int)); // allocated free(x); // free memory once, OK free(x); // free repeatedly, bad

2KB 2KB allocated freed Heap Heap free(x) free(x) Undefined (free) (free) Error

Stack Stack 2KB x 2KB(invalid) 16KB 16KB x Address Space Address Space

9/14/21 CMPU 334 -- Operating Systems 13 Other Memory APIs: calloc()

#include

void *calloc(size_t nmemb, size_t size)

• Allocate memory on the heap and zeroes it before returning • Arguments • nmemb: number of elements to allocate • size: size of one element • Returns • Success: a void type pointer to the memory block allocated by calloc • Fail: a null pointer

9/14/21 CMPU 334 -- Operating Systems 14 Other Memory APIs: realloc()

#include

void *realloc(void *ptr, size_t size)

• Change the size of memory block • A pointer returned by realloc may be either the same as ptr or a new • Argument • void *ptr: Pointer to memory block allocated with malloc, calloc, or realloc • size_t size: New size for the memory block(in bytes) • Return • Success: Void type pointer to the memory block • Fail: Null pointer

9/14/21 CMPU 334 -- Operating Systems 15 System Calls

#include

int brk(void *addr) void *sbrk(intptr_t increment);

• malloc library call uses brk system call • brk is called to expand the program’s break • break: The addressof the end of the heap in address space • sbrk increases the break by increment • Programmers should never directly call either brk or sbrk

9/14/21 CMPU 334 -- Operating Systems 16 Free space management

• How should free space be managed? • Variable-sized requests

• How can we minimize fragmentation

• Time and space requirements for allocation algorithms

9/14/21 CMPU 334 -- Operating Systems 17 Splitting

• Finding a free chunk of memory that can satisfy the request and splitting it into two • When request for memory allocation is smaller than the size of free chunks

30- heap: free used free 0 10 20 30

addr:0 addr:20 free list: head len:10 len:10 NULL

9/14/21 CMPU 334 -- Operating Systems 18 Splitting(Cont.)

• Two 10-bytes free segment with 1-byte request

30-byte heap: free used free 0 10 20 30

addr:0 addr:20 free list: head len:10 len:10 NULL

��������� �� − ���� ���� �������

30-byte heap: free used free 0 10 20 21 30

addr:0 addr:21 free list: head len:10 len:9 NULL

9/14/21 CMPU 334 -- Operating Systems 19 Coalescing

• If a user requests memory that is bigger than the free chunk size, the list will not find such a free chunk • Coalescing: Merge returning a free chunk with existing chunks into a large single free chunk if addresses of them are nearby

addr:10 addr:0 addr:20 head len:10 Len:10 len:10 NULL

���������� ���� ������

addr:0 head len:30 NULL

9/14/21 CMPU 334 -- Operating Systems 20 Tracking The Size of Allocated Regions

• The to free(void *ptr) does not take a size parameter • How does the library know the size of memory region that will be back into free list? • Most allocators store extra information in a header block

ptr = malloc(20);

The header used by malloc library

ptr

The 20 bytes returned to caller

An Allocated Region Plus Header

9/14/21 CMPU 334 -- Operating Systems 21 The Header of Allocated Memory Chunk

• The header minimally contains the size of the allocated memory region • The header may also contain • Additional pointers to speed up deallocation • A magic number for integrity checking

hptr size: 20 magic: 1234567 typedef struct __header_t { ptr int size; int magic; The 20 bytes } header_t; returned to caller

A Simple Header Specific Contents Of The Header

9/14/21 CMPU 334 -- Operating Systems 22 The Header of Allocated Memory Chunk(Cont.)

• The size for free region is the size of the header plus the size of the space allocated to the user • If a user request N bytes, the library searches for a free chunk of size N plus the size of the header

• Simple pointer arithmetic to find the header pointer

void free(void *ptr) { header_t *hptr = (char *)ptr – sizeof(header_t); }

9/14/21 CMPU 334 -- Operating Systems 23 Embedding a Free List

• The memory-allocation library initializes the heap and puts the first element of the free list in the free space • The library can’t use malloc() to build a list within itself • Description of a node in the list typedef struct __node_t { int size; struct __node_t *next; } node_t; • Building the heap and creating a free list • Assume the heap is built with mmap() system call

// mmap() returns a pointer to a chunk of free space node_t *head = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); head->size = 4096 - sizeof(node_t); head->next = NULL;

9/14/21 CMPU 334 -- Operating Systems 24 A Heap With One Free Chunk

// mmap() returns a pointer to a chunk of free space node_t *head = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); head->size = 4096 - sizeof(node_t); head->next = NULL;

[virtual address: 16KB] head header: size field size: 4088

next: 0 header: next field(NULL is 0)

■ ■ ■ the rest of the 4KB chunk

9/14/21 CMPU 334 -- Operating Systems 25 Embedding A Free List: Allocation

• If a chunk of memory is requested, the library will first find a chunk that is large enough to accommodate the request

• The library will • Split the large free chunk into two • One for the request and the remaining free chunk • Shrink the size of free chunk in the list

9/14/21 CMPU 334 -- Operating Systems 26 Embedding A Free List: Allocation(Cont.)

• Example: a request for 100 bytes by ptr = malloc(100) • Allocating 108 bytes out of the existing one free chunk • shrinking the one free chunk to 3980(4088 minus 108)

A 4KB Heap With One Free Chunk A Heap : After One Allocation

head size: 100 size: 4088 magic: 1234567 next: 0 ptr

the rest of ■ ■ ■ ■ ■ ■ the 100 bytes now allocated the 4KB chunk head size: 3980 next: 0

■ ■ ■ the free 3980 byte chunk

9/14/21 CMPU 334 -- Operating Systems 27 Free Space With Chunks Allocated

size: 100 [virtual address: 16KB] 8 bytes header magic: 1234567

■ ■ ■ 100 bytes still allocated

size: 100 magic: 1234567 sptr

■ ■ ■ 100 bytes still allocated (but about to be freed) size: 100 magic: 1234567

■ ■ ■ 100 bytes still allocated head size: 3764 next: 0

■ ■ ■ The free 3764-byte chunk

Free Space With Three Chunks Allocated

9/14/21 CMPU 334 -- Operating Systems 28 Free Space With free()

• Example: free(sptr) [virtual address: 16KB] • The 100 byte chunk is put back size: 100 into the free list magic: 1234567 • sptr->next == old head ■ ■ ■ 100 bytes still allocated head • It is now the head of the free list size: 100 next: 16708 sptr • The free list will start with the (now a free chunk of ■ ■ ■ small chunk memory) size: 100 magic: 1234567

■ ■ ■ 100 bytes still allocated

size: 3764 next: 0

■ ■ ■ The free 3764-byte chunk

9/14/21 CMPU 334 -- Operating Systems 29 Free Space With Freed Chunks

• Let’s assume that the last two in-use chunks are freed

[virtual address: 16KB] size: 100 • External Fragmentation occurs next: 16492 • Coalescing is needed in the list ■ ■ ■ (now free)

size: 100 next: 16708

■ ■ ■ (now free) head size: 100 next: 16384

■ ■ ■ (now free)

size: 3764 next: 0

■ ■ ■ The free 3764-byte chunk

9/14/21 CMPU 334 -- Operating Systems 30 Growing The Heap

• Most allocators start with a small-sized heap and then request more memory from the OS when they run out • e.g., sbrk(), brk() in most UNIX systems

(not in use)

Heap Heap Heap break sbrk() break (not in use)

Address Space Address Space

9/14/21 CMPU 334 -- Operating Systems 31 Managing Free Space: Basic Strategies • Best Fit: • Finding free chunks that are big or bigger than the request • Returning the one of smallest in the chunks in the group of candidates • Worst Fit: • Finding the largest free chunks and allocation the amount of the request • Keeping the remaining chunk on the free list • First Fit: • Finding the first chunk that is big enough for the request • Returning the requested amount and remaining the rest of the chunk • Next Fit: • Finding the first chunk that is big enough for the request • Searching at where one was looking at instead of the beginning of the list

9/14/21 CMPU 334 -- Operating Systems 32 Examples of Basic Strategies

• Allocation Request Size 15

head 10 30 20 NULL

• Result of Best-fit

head 10 30 5 NULL

• Result of Worst-fit

head 10 15 20 NULL

9/14/21 CMPU 334 -- Operating Systems 33 Explicit Free List

Block Size a/f Block Size a/f

pred (predecessor) succ (successor) Payload

Padding (optional) Padding (optional)

Block Size a/f Block Size a/f

Allocated Block Free Block

9/14/21 CMPU 334 – Operating Systems 34 Other Approaches

• Segregated List • Keeping free chunks in different size in a separate list for the size of popular request • New Complication: • How much memory should dedicate to the pool of memory that serves specialized requests of a given size? • Slab allocator handles this issue • Slab Allocator • Allocate a number of object caches • The objects are likely to be requested frequently • e.g., locks, file-system inodes, etc. • Keeps freed objects in a particular list in their initialized state • Request some memory from a more general memory allocator when a given cache is running low on free space

9/14/21 CMPU 334 -- Operating Systems 35 Other Approaches

• Binary Buddy Allocation • The allocator divides free space by two until a block that is big 64 KB enough to accommodate the request is found 32 KB 32 KB • Buddy allocation can suffer from internal fragmentation 16 KB 16 KB • Buddy system makes coalescing simple 8 KB 8 KB

• Coalescing two blocks in to the 64KB free space for 7KB request next level of block

9/14/21 CMPU 334 -- Operating Systems 36