V Lecture 16 — memory management, hw5
* how do malloc and free work?
V OS
V operating system provides system calls
* a system call is a function programs use to request things from the operating system
* these handle large chunks of contiguous memory
V for example brk and sbrk in Linux
* both modify the size of the heap, giving a program more or less memory to work with
* this is clumsy and very low-level, which is why the C standard library give us nicer functions to work with
V free list
* the data structure you will use in hw5 to support your versions of malloc and free
V linked list of available blocks of memory
* each block knows its size and the location of the next block
* blocks kept in order of ascending memory address
V for each request, scan down the list for a block large enough to fulfill the request
* remove the block from the list and return it
V what if the block is much larger than the request?
* split the block in two, returning one of appropriate size
V to free a block, find where it should go in the list by memory address and insert it
V combine it with previous and next blocks if they are adjacent
* important to prevent fragmentation
V How will we keep track of the size of a block?
* struct free_block {
uintptr_t size;
struct free_block *next;
};
* each block will have a struct like this as a header
* when we return a block, we’ll actually return a pointer to the part of the block past the header
* this way, the header will still be intact when the block is freed
V where will your free list get its initial memory? How will your free list get more memory if it doesn’t have a big enough block?
* malloc
V getmem
* block addresses made up to be convenient rather than realistic
V example: request 100 bytes
block0 @ 0x000, size 32 bytes
block1 @ 0x070, size 112 bytes
block2 @ 0x110, size 64 bytes
* block1 is returned, no splitting needed:
block0 @ 0x000, size 32 bytes
block1 @ 0x110, size 64 bytes
* address returned: 0x080
V exercise: request 10 bytes
block0 @ 0x000, size 64 bytes
block1 @ 0x070, size 112 bytes
block2 @ 0x110, size 64 bytes
* block0 @ 0x020, size 32 bytes
block1 @ 0x070, size 112 bytes
block2 @ 0x110, size 64 bytes
or
block0 @ 0x000, size 32 bytes
block1 @ 0x070, size 112 bytes
block2 @ 0x110, size 64 bytes
* block0 can be split two different ways
* address returned: 0x010 or 0x040
V exercise: request 200 bytes
block0 @ 0x0000, size 64 bytes
block1 @ 0x0700, size 112 bytes
block2 @ 0x8000, size 64 bytes
V block0 @ 0x0000, size 64 bytes
block1 @ 0x0700, size 112 bytes
block3 @ 0x1000, size 3872 bytes
block2 @ 0x8000, size 64 bytes
* new 4-kilobyte (4096-byte) block of memory allocated via malloc (arbitrarily assumed address of 0x1000), placed in the appropriate position in the list, and then split to satisfy the request
V freemem
* block addresses made up to be convenient rather than realistic
V example: freeing 0x040 (block @ 0x030, size 32 bytes)
block0 @ 0x000, size 32 bytes
block1 @ 0x070, size 112 bytes
block2 @ 0x110, size 64 bytes
* block0 @ 0x000, size 32 bytes
block @ 0x030, size 32 bytes
block1 @ 0x070, size 112 bytes
block2 @ 0x110, size 64 bytes
coalesce to get
block0 @ 0x000, size 80 bytes
block1 @ 0x070, size 112 bytes
block2 @ 0x110, size 64 bytes
* 0x000 + 0x10 (for header) + 0x20 (size of block0) = 0x030, so we combine block0 and block
* 0x000 + 0x10 + 0x50 = 0x060, so we don’t need to combine block0 and block1
V exercise: freeing 0x100 (block @ 0x0f0, size 16 bytes)
block0 @ 0x000, size 32 bytes
block1 @ 0x070, size 112 bytes
block2 @ 0x110, size 64 bytes
* block0 @ 0x000, size 32 bytes
block1 @ 0x070, size 224 bytes
* 0x070 + 0x10 (for header) + 0x70 (size of block1) = 0x0f0, so we combine block1 and block
* 0x070 + 0x10 (for header) + 0x90 (size of block0) = 0x110, so we combine block1 and block2
* could combine these in either order
V future topics
* lecture going over midterm?
* stack smashing
* testing
* C++
* concurrency