Download presentation
Presentation is loading. Please wait.
Published byRalph Jared Norris Modified over 9 years ago
1
Heap Management
2
What is really stored on the heap? Housekeeping Users Data Buffer Next Block Data Housekeeping 0x7000 0x7008 int main() { int *x,*y; x=(int*)malloc(2*sizeof(int)); //new heap assert(x); printf("%p\n",x); //How does malloc function know where to put y? y=(int*)malloc(sizeof(int)); assert(y); //How does free function know how much to free? free(x);
3
What is really stored on the heap? "housekeeping data" stored in area before your data: size field- holds the number of bytes of users data in this block (user's request + some buffer) next field- if block in "use" it will be null.. otherwise holds the address of the next free block.. Thus a "linked list" of free blocks is formed inside the heap. Starting at address given by the "free list pointer".. malloc can search through free blocks. Housekeeping Users Data Buffer Next Block Data Housekeeping 0x7000 0x7008
4
What is really stored on the heap? A "reference count" of number of pointers pointing to this block in user's program could also be in the housekeeping data. What would we use the reference count for? Housekeeping Users Data Buffer Next Block Data Housekeeping 0x7000 0x7008
5
What does the heap look like? malloc() searches the free list for a block that is big enough. If none is found, more memory is requested from the operating system. free() checks if the blocks adjacent to the freed block are also free If so, adjacent free blocks are merged in to a single, larger free block. Otherwise, the freed block is just added to the free list.
6
What does the heap look like? If there are multiple free blocks of memory that are big enough for some request, how do we choose which one to use? –best-fit: choose the smallest block that is big enough for the request –first-fit: choose the first block we see that is big enough –next-fit: like first-fit but remember where we finished searching and resume searching from there
7
What does the heap look like? int main() { int *x,*y,*z; x=(int*)malloc(20*sizeof(int)); //new heap assert(x); y=(int*)malloc(10*sizeof(int)); assert(y); free(x); z=(int*)malloc(10*sizeof(int)); assert(z); What does our heap look like if we use first fit? What if we use next fit?
8
the heap starts here at 7000 x=7008 this is 92 bytes here size=92 bytes next free block 20*4 + 12 buffer NULL 20 integers and 12 bytes of buffer... size=52 bytes next free block 10*4 + 12 buffer NULL 7100 y=7108 this is 52 bytes here 10 integers and 12 bytes of buffer... size=xxxx bytes next free block (heap size-160) NULL 7160 this is heap size - 168 bytes here Heap Free List Pointer = 7160 The Heap looks like this after malloc 'ing x and y before x is free d.
9
the heap starts here at 7000 this is 92 bytes here size=92 bytes next free block 20*4 + 12 buffer NULL FREE FREE FREE FREE FREE FR size=52 bytes next free block 10*4 + 12 buffer NULL 7100 y=7108 this is 52 bytes here 10 integers and 12 bytes of buffer... size=xxxx bytes next free block (heap size-160) NULL 7160 this is heap size - 168 bytes here Heap Free List Pointer = 7000 The Heap looks like this x is free d before z is malloc 'ed.
10
the heap starts here at 7000 z=7008 this is 52 bytes here size=52 bytes next free block 20*4 + 12 buffer NULL 10 integers and 12 bytes of buffer... size=32 bytes next free block 7160 7060 this is 32 bytes here FREE FREE FREE FREE FREE size=xxxx bytes next free block (heap size-160) NULL 7160 this is heap size - 168 bytes here size=52 bytes next free block 10*4 + 12 buffer NULL 7100 y=7108 this is 52 bytes here 10 integers and 12 bytes of buffer... Heap Free List Pointer = 7060
11
the heap starts here at 7000 this is 92 bytes here size=92 bytes next free block 7220 FREE FREE FREE FREE FREE size=xxxx bytes next free block (heap size-220) NULL 7220 this is heap size - 220 bytes here size=52 bytes next free block 10*4 + 12 buffer NULL 7100 y=7108 this is 52 bytes here 10 integers and 12 bytes of buffer... Heap Free List Pointer = 7000 size=52 bytes next free block 10*4 + 12 buffer NULL 7160 z=7168 this is 52 bytes here 10 integers and 12 bytes of buffer...
12
GNU malloc.c - Simplified for old ver.
13
_heapinfo[0] _heapinfo[1] … _heapinfo[2 10 -1] 4 th block 5 st block 6 nd block 7 rd block 8 th block 9 th block … … HEAP = 2 22 bytes BLOCKSIZE = 2 12 bytes _heapbase 00 10 20 33 42 50 60 70 80 90 100 110 _fragblocks 0nextprev 1nextprev 2nextprev 3nextprev 4nextprev 5nextprev 6nextprev 7nextprev 8nextprev 9nextprev 10nextprev 11nextprev _fraghead 0 12 24 12288 16376 20484 Data Structure for malloc.c
14
_fragblocks A global array of 12 integers holds the number of 4096 bytes blocks containing fragments of a certain size that have been allocated. [11] is number of 4096 byte blocks containing 2048 byte fragments… [10] is number of 4096 bytes blocks containing for 1024 byte fragments Note that frag here is allocated frag, not free frag. int _fragblocks[BLOCKLOG]; //BLOCKLOG = log 2 (BLOCKSIZE)
15
_fradhead A global array of 12 structures holds the pointer to the first and the last frag block of a given size: 2 log Note that frag here is free frag. struct list _fraghead[BLOCKLOG]; //list{int *next; int prev;} NEXT PREV NEXT PREV 0 0 _fraghead[log]
16
How the real malloc does it… The real malloc actually uses blocks of standardized size to fill your request. –The standard block is 4096 bytes. –Standard blocks can be broken up in to smaller “frag blocks” of sizes 8, 16, 32, 64, 128, 256, 512, 1024, 2048 bytes long. –For example: If you ask for 13 bytes you’ll get a 16 byte fragment. –This is a trade off between speed and space wastage. Why the smallest free frag size is 8? Why not 4 or other number?
17
_heapinfo busy –fragmented type: frag size num of free frag first free frag –allocated as whole type: a block the num of contiguous blocks which are allocated free –the num of contiguous blocks which are free –next free cluster –prev free cluster
18
Look at source code – malloc.h $tar –xvf malloc_debug.tar $cd malloc_debug/malloc $vim malloc.h
19
extern What if I want global variables to be accessible for use in another file (section of my code)? extern int flag; extern- lets the compiler know that it won’t be able to figure out where the variable is located at compile time. (unresolved reference) Why? The compiler only looks at the file you are trying to compile- and doesn’t have the “big picture” yet about the other files you’re compiling and putting together. NACHOS will have about 30 source files that you will compile to build the OS. (LINUX kernel has 100s)
20
extern continued The Linker does have the “big picture” and responsible for “linking” together all of the object files made by the compiler and making a single executable. In the case of extern the compiler will send a message to the linker saying “I’m not really sure where this variable is located- it may be in another file - can you find it?”
21
Function Pointers typedef enum bool {FALSE, TRUE} bool; bool greaterthan(int x,int y) { return (x>y); } bool lessthan(int x, int y) { return (x<y); } bool foo(bool (*compare)(int,int), int x, int y) { return( (*compare)(x,y)); } int main() { if (foo(lessthan,3,5)) printf("3 is less than 5\n"); }
22
Function Pointers #include void function (int x) {printf("%d",x);} void (*func_pointer)(int); int main() { int choice; int x = 5; void (*func_pointer)(int) = function; (*func_pointer)(int); }
23
Function Pointers To declare a function pointer : return type (*function_ptr) (function inputs); extern void *(*_morecore)(long); extern- this function may be defined or used outside this file The return type is a void* The input to the function must be a long. The function is referred to via the pointer _morecore
24
This is a function prototype: /* Default value of previous. */ extern void *_default_morecore(long); This function takes in a long and returns a void* and is called _default_morecore This matches the type of a _morecore function pointer. The _default_morecore function actually goes and gets more memory for the heap.
25
Function Pointers cont’d So far we’ve declared a function pointer extern void *(*_morecore)(long); We’ve given a function prototype extern void *_default_morecore(long) And then we eventually assign the pointer… Code from malloc.c /* How to really get more memory. */ void *(*_morecore)(long) = _default_morecore;
26
What do these do? #define INT_BIT (CHAR_BIT * sizeof (int)) You may assume that CHAR_BIT is 8 in our architecture. #define BLOCKLOG (INT_BIT > 16 ? 12 : 9) What value does BLOCKLOG get? #define BLOCKSIZE (1 << BLOCKLOG) What value does BLOCKSIZE get? Shift left 1 how many times? #define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE)
27
Heap Initial Size /* Determine the amount of memory spanned by the initial heap table (not an absolute limit). */ #define HEAP (INT_BIT > 16 ? 4194304 : 65536)
28
Unions Most of the programmers in the world think that Unions were a bad idea. That’s probably why Java got rid of them. Unfortunately- there’s lots of poorly written code out there with unions in it. Including malloc() Unions allow you to store one of several different types in a given storage location. Unfortunately- you have to remember which type that you stored in the location.
29
Union Example typedef union Number { int x; double y; } Number_T; int main() { Number_T value; value.x=100; printf ("X is %d and Y is %g\n", value.x,value.y); value.y=100.0; printf ("X is %d and Y is %g\n", value.x,value.y); } X is 100 and Y is 6.15928e-306 X is 0 and Y is 100.000000 Thus in a Number_T we can store either an int or a double and can change back and forth
30
union info { struct { int type; union { struct { int nfree; int first; } frag; int size; } info; } busy; struct { int size; int next; int prev; } free; }; An info is either: This ( busy struct) Or This ( free struct)
31
union info { struct { int type; union { struct { int nfree; int first; } frag; int size; } info; } busy; struct { int size; int next; int prev; } free; }; A busy is: an integer And either: frag structure or another integer
32
What does this do? #define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1) #define ADDRESS(B) ((void *) (((B) - 1) * BLOCKSIZE + _heapbase))
33
Debug malloc.c $ cd ~/malloc_debug $ddd main Menu ‘data’->’Status Display’ –Backtrace of the stack Menu ‘Edit’->’Preferences…’->’Source’ –Display Source Line Numbers
34
main.c //Allocate the first memory under your control. int *x; //new heap x=(int*)malloc(20*sizeof(int)); free(x);
35
Step into malloc func HEAP = 2 22 bytes BLOCKSIZE = 2 12 bytes _heapbase 00 10 20 30 40 50 60 70 80 90 100 110 _fragblocks 0nextprev 100 200 300 400 500 600 700 800 900 1000 1100 _fraghead
36
Step into initialize() heapsize = HEAP / BLOCKSIZE; –Figures out how many blocks we have We have 2 10 blocks. In other words, 2 10 _heapinfo elements.
37
align(heapsize * sizeof (union info)); HEAP = 2 22 bytes BLOCKSIZE = 2 12 bytes _heapbase 00 10 20 30 40 50 60 70 80 90 100 110 _fragblocks 0nextprev 100 200 300 400 500 600 700 800 900 1000 1100 _fraghead _heapinfo[0] _heapinfo[1] … _heapinfo[2 10 -1] 0 12 24
38
_heapbase = (char *) _heapinfo; HEAP = 2 22 bytes BLOCKSIZE = 2 12 bytes _heapbase 00 10 20 30 40 50 60 70 80 90 100 110 _fragblocks 0nextprev 100 200 300 400 500 600 700 800 900 1000 1100 _fraghead _heapinfo[0] _heapinfo[1] … _heapinfo[2 10 -1] 0 12 24
39
Go back to malloc 126: Check for request for 0 bytes 129: Check to see if size requested is < 8 Bytes 133: Is the request <= 2048 bytes?
40
136: --size; 137: for (log=1; (size>>=1)!=0; ++log) At the end the following will be true: 2 log >= size > 2 log-1 For example: size = 80 in binary size = 1010000 --size = 1001111 log = 7 Why --size?
41
142: if ((next = _fraghead[log].next) != 0) We check to see if there are any frag blocks of our size available. (Initially no frag blocks. _fraghead[log].next is all 0’s because…)
42
158: result = malloc(BLOCKSIZE) We make a recursive call to malloc requesting a block of 4096 bytes. Step into malloc again. We do same checks (initialize, size, etc.) We go in to large block routine – 179: else
43
184: blocks = BLOCKIFY(size) We get the number of blocks this size corresponds to. In our case: –size = 4096 –blocks = 1
44
187: start = block = _heapindex _heapindex points the free block which is in the free block link. _heapinfo[0] _heapinfo[9] _heapinfo[17]_heapinfo[12] _heapinfo[7]_heapinfo[3] _heapindex
45
188: if (block == start) We searched through the linked list, and did not find any memory block large enough to meet our request. We need to get more memory from system.
46
line 193 -- 203 Suppose we need 4 more blocks _heapinfo[0] _heapinfo[1] … _heapinfo[2 10 -1] 4 th block 5 st block 6 nd block 7 rd block _heapinfo[0] _heapinfo[1] … _heapinfo[2 10 -1] 4 th block 5 st block 6 nd block 7 rd block 8 th block 9 th block We just need to ask for 2 more.
47
204: result = morecore(blocks * BLOCKSIZE) _heapbase 00 10 20 30 40 50 60 70 80 90 100 110 _fragblocks 0nextprev 100 200 300 400 500 600 700 800 900 1000 1100 _fraghead _heapinfo[0] _heapinfo[1] … _heapinfo[2 10 -1] 1 st Block 0 12 24 result
48
Go back to malloc again! Now we are at line 158 161: ++_fragblocks[log] –We increase the count of our fragment sized blocks by one.
49
Line 164 -171 0 NEXT PREV 31 frags each frag has 128 bytes 1 st block 0nextprev 100 200 300 400 500 600 70 800 900 1000 1100 _fraghead NEXT PREV NEXT PREV NEXT PREV NEXT PREV 0
50
Line 174 - 177 Fill in _heapinfo. Return the result. Done!
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.