CS356: Discussion #11
Dynamic Memory, Allocation Lab and Linking
Illustrations from CS:APP3e textbook
CS356 : Discussion #11 Dynamic Memory, Allocation Lab and Linking - - PowerPoint PPT Presentation
CS356 : Discussion #11 Dynamic Memory, Allocation Lab and Linking Illustrations from CS:APP3e textbook malloc and free in action Each square represents 4 bytes. malloc returns addresses at multiples of 8 bytes (64 bit). If there is a problem,
Illustrations from CS:APP3e textbook
Each square represents 4 bytes. malloc returns addresses at multiples of 8 bytes (64 bit). If there is a problem, malloc returns NULL and sets errno. malloc does not initialize to 0, use calloc instead.
Explicit allocators like malloc
Goal 1. Maximize throughput: (# completed requests) / second
and free with running time O(1) Goal 2. Maximize peak utilization: max{ allocated(t) : t ⩽ T} / heapsize(T)
Each square represents 4 bytes Header: (block size) / (allocated)
Assume:
Block size (in bytes) and block header (in hex) for blocks allocated by the following sequence: malloc(1) malloc(5) malloc(12) malloc(13)
○ First Fit: First block with enough space. ⇒ retains large blocks at the end of the list, but must skip many ○ Next Fit: First block with enough space, start from last position. ⇒ no need to skip small blocks at start, but worse memory utilization ○ Best Fit: Smallest block with enough space. ⇒ generally better utilization, but slower (must check all blocks)
○ Assign entire block ⇒ internal fragmentation (ok for good fit) ○ Split the block at 2-word boundary, add another header
What to do when no free block is large enough?
○ Returns a pointer to the start of the new area
○ Can coalesce both previous and following block ○ Coalescing when freeing blocks is O(1) but allows thrashing ○ Boundary tag Use a “footer” at the end of each (free) block to fetch previous block
Allocation time is O(#blocks) for implicit lists...
Much faster when memory is full, but lower memory utilization.
16/0 16/0 24/1 24/1 16/0 ⨯ 16/0 16/0 ⨯ 16/0 0/1
○ No coalescing: just add element to list head ○ Coalescing: remove contiguous blocks from free list, merge them, add the new free block to list head
Free List Root
To reduce allocation time:
1-8 9-16 17-32 33-64 65-∞
Simple Segregated
Segregated Fits
Advantages
You only need to modify mm.c
#include <stdio.h> int mm_init (void); // init heap: 0 if successful, -1 if not void *mm_malloc (size_t size);// 8-byte aligned non-overlapping heap region void mm_free (void *ptr); // frees a pointer returned by mm_malloc void *mm_realloc(void *ptr, size_t size); /* mm_realloc(ptr, size)
(contract: old data unchanged, new data uninitialized) */
The memlib.c package simulates the OS memory system.
void *mem_sbrk(int incr); // extend heap, return pointer to new area void mem_reset_brk(void); // reset brk, release all heap memory void *mem_heap_lo(void); // address of first heap byte void *mem_heap_hi(void); // address of last heap byte == brk-1 size_t mem_heapsize(void); // heap size in bytes size_t mem_pagesize(void); // system page size
Note that mem_sbrk accepts only a positive integer (cannot shrink the heap).
To debug, scan the heap
Save the checks inside int mm_check(void) (return 0 if inconsistent)
Trace Driver: mtest.c
Trace File Format
<num_ids> /* number of request id's */ <num_ops> /* number of requests (operations) */
a <id> <bytes> /* ptr_<id> = malloc(<bytes>) */ r <id> <bytes> /* realloc(ptr_<id>, <bytes>) */ f <id> /* free(ptr_<id>) */
2 5 a 0 512 a 1 128 r 0 640 f 1 f 0 Meaning
100 points for performance ○ memory utilization = peak memory usage / heap size (at most 1) ○ throughput = operations / second ○ performance index (w = 0.6)
Implementations include but are not limited to
Additional rules
Storage Class Specifiers
Function prototypes are extern by default; local variables can be static (bad)
gcc -c main.c swap.c gcc -o prog main.o swap.o ./prog
With extern specifier
With Initialization (Strong Symbol)
○ Linking error if another unit initializes a variable with the same name ○ No error if the other unit defines a weak symbol (no initialization) Without Initialization (Weak Symbol)
○ Shared if another unit defines a variable with the same name No checks on global variable types: data types may not match (bad!) ○ Also no checks on function prototypes of external functions... ○ Checks on types/prototypes if linking optimization -ftlo is enabled ○ Common strategy: each unit includes its own prototypes/externs
$ gcc -Wall -Wextra -std=c99 main.c swap.c -o prog $ ./prog z = 11223344 x = 11227788 y = 55663344 z = 11220000
/* main.c */ #include <stdio.h> int z = 0x11223344; void swap(int *x, int *y); int main() { int x = 0x11223344; int y = 0x55667788; printf("z = %x\n", z); swap(&x, &y); printf("x = %x\n", x); printf("y = %x\n", y); printf("z = %x\n", z); } /* swap.c */ short z; void swap(short *x, short *y) { z = 0; short tmp = *x; *x = *y; *y = tmp; }
$ gcc -Wall -Wextra -std=c99 -flto main.c swap.c -o prog main.c:4:6: warning: type of ‘swap’ does not match original declaration [..] swap.c:1:7: warning: type of ‘z’ does not match original declaration [..] main.c:3:5: note: type ‘int’ should match type ‘short int’
/* main.c */ #include <stdio.h> int z = 0x11223344; void swap(int *x, int *y); int main() { int x = 0x11223344; int y = 0x55667788; printf("z = %x\n", z); swap(&x, &y); printf("x = %x\n", x); printf("y = %x\n", y); printf("z = %x\n", z); } /* swap.c */ short z; void swap(short *x, short *y) { z = 0; short tmp = *x; *x = *y; *y = tmp; }
$ gcc -Wall -Wextra -std=c99 \ main.c swap.c -o prog $ ./prog z = 11223344 x = 55667788 y = 11223344 z = 0 Strategy: Each unit includes its own prototypes/declarations.
in compile errors within a unit
avoid double (or recursive) inclusion of headers
results in a linking error
/* main.c */ #include "main.h" int z = 0x11223344; int main() { int x = 0x11223344; int y = 0x55667788; printf("z = %x\n", z); swap(&x, &y); printf("x = %x\n", x); printf("y = %x\n", y); printf("z = %x\n", z); } /* swap.c */ #include "swap.h" void swap(int *x, int *y) { z = 0; int tmp = *x; *x = *y; *y = tmp; } /* main.h */ #ifndef MAIN_H #define MAIN_H #include <stdio.h> #include "swap.h" extern int z; #endif /* MAIN_H */ /* swap.h */ #ifndef SWAP_H #define SWAP_H #include "main.h" void swap(int *x, int *y); #endif /* SWAP_H */
○ Global Symbols: Non-static, global variables and functions ○ External Global Symbols: Used but not defined in a unit ○ Local Symbols: Static variables and functions (used only in this unit)
■ Local variables are not local symbols! (Not involved in linking) ■ Errors for duplicate definition of local symbols, duplicate global symbols with initializations (strong symbols)
Three kinds of object files:
In Linux, executable files have the ELF format (Executable & Linked Format)
.text binary code .rodata constants like strings .data initialized global/static vars .bss uninitialized global/static variables (no space in .o) .symtab symbol table (functions and global variables) .rel.text relocation info .debug, .line: symbol table for locals and other definitions (included with -g) .strtab Table of all the strings used by other headers
added to executable at linking time
code into memory
new library version (e.g., with bug fixes)
with runtime location of code
same code (as read-only areas)
new version is used