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 bytes) • 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 null pointer
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”; //character 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 *c *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-byte 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 interface 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