Heap Management

50
Heap Management

description

Heap Management. What is really stored on the heap?. 0x7000. Housekeeping Users Data Buffer Next Block Data Housekeeping. 0x7008. int main() { int *x,*y; x=(int*)malloc(2*sizeof(int)); //new heap - PowerPoint PPT Presentation

Transcript of Heap Management

Page 1: Heap Management

Heap Management

Page 2: Heap Management

What is really stored on the heap?

Housekeeping Users Data Buffer Next BlockData 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);

Page 3: Heap Management

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 BlockData Housekeeping

0x7000

0x7008

Page 4: Heap Management

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 BlockData Housekeeping

0x7000

0x7008

Page 5: Heap Management

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.

Page 6: Heap Management

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

Page 7: Heap Management

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?

Page 8: Heap Management

the heap starts here at 7000 x=7008 this is 92 bytes here

size=92 bytes next free block20*4 + 12 buffer NULL

20 integers and 12 bytes of buffer...

size=52 bytes next free block10*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 freed.

Page 9: Heap Management

the heap starts here at 7000 this is 92 bytes here

size=92 bytes next free block20*4 + 12 buffer NULL

FREE FREE FREE FREE FREE FR

size=52 bytes next free block10*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 freed before z is malloc'ed.

Page 10: Heap Management

the heap starts here at 7000 z=7008 this is 52 bytes here

size=52 bytes next free block20*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 block10*4 + 12 buffer NULL

7100 y=7108 this is 52 bytes here

10 integers and 12 bytes of buffer...

Heap Free List Pointer = 7060

Page 11: Heap Management

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 block10*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 block10*4 + 12 buffer NULL

7160 z=7168 this is 52 bytes here

10 integers and 12 bytes of buffer...

Page 12: Heap Management

GNU malloc.c- Simplified for old ver.

Page 13: Heap Management

_heapinfo[0]

_heapinfo[1]

_heapinfo[210-1]

4th block

5st block

6nd block

7rd block

8th block

9th block

HEAP = 222 bytes

BLOCKSIZE

= 212 bytes

_heapbase

0 0

1 0

2 0

3 3

4 2

5 0

6 0

7 0

8 0

9 0

10 0

11 0

_fragblocks

0 next prev

1 next prev

2 next prev

3 next prev

4 next prev

5 next prev

6 next prev

7 next prev

8 next prev

9 next prev

10 next prev

11 next prev

_fraghead

0

12

24

12288

16376

20484

Data Structure for malloc.c

Page 14: Heap Management

_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 = log2(BLOCKSIZE)

Page 15: Heap Management

_fradhead• A global array of 12 structures holds the

pointer to the first and the last frag block of a given size: 2log

• Note that frag here is free frag.

struct list _fraghead[BLOCKLOG];//list{int *next; int prev;}

NEXT PREV NEXT NEXT NEXTPREV PREV PREV

0 0

_fraghead[log]

Page 16: Heap Management

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?

Page 17: Heap Management

_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

Page 18: Heap Management

Look at source code – malloc.h

• $tar –xvf malloc_debug.tar

• $cd malloc_debug/malloc

• $vim malloc.h

Page 19: Heap Management

externWhat 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)

Page 20: Heap Management

extern continuedThe 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?”

Page 21: Heap Management

Function Pointerstypedef 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");}

Page 22: Heap Management

Function Pointers#include <stdio.h>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);}

Page 23: Heap Management

Function PointersTo 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

Page 24: Heap Management

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.

Page 25: Heap Management

Function Pointers cont’dSo 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;

Page 26: Heap Management

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)

Page 27: Heap Management

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)

Page 28: Heap Management

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.

Page 29: Heap Management

Union Exampletypedef 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-306X 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

Page 30: Heap Management

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)

Page 31: Heap Management

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 integerAnd either:frag structureor another integer

Page 32: Heap Management

What does this do?

#define BLOCK(A) (((char *) (A) - _heapbase) / BLOCKSIZE + 1)

#define ADDRESS(B) ((void *) (((B) - 1) * BLOCKSIZE + _heapbase))

Page 33: Heap Management

Debug malloc.c

• $ cd ~/malloc_debug

• $ddd main

• Menu ‘data’->’Status Display’– Backtrace of the stack

• Menu ‘Edit’->’Preferences…’->’Source’– Display Source Line Numbers

Page 34: Heap Management

main.c

• //Allocate the first memory under your control.

• int *x;

//new heap

• x=(int*)malloc(20*sizeof(int));

• free(x);

Page 35: Heap Management

Step into malloc func

HEAP = 222 bytes

BLOCKSIZE

= 212 bytes

_heapbase

0 0

1 0

2 0

3 0

4 0

5 0

6 0

7 0

8 0

9 0

10 0

11 0

_fragblocks

0 next prev

1 0 0

2 0 0

3 0 0

4 0 0

5 0 0

6 0 0

7 0 0

8 0 0

9 0 0

10 0 0

11 0 0

_fraghead

Page 36: Heap Management

Step into initialize()

• heapsize = HEAP / BLOCKSIZE;– Figures out how many blocks we have

• We have 210 blocks.

• In other words, 210 _heapinfo elements.

Page 37: Heap Management

align(heapsize * sizeof (union info));

HEAP = 222 bytes

BLOCKSIZE

= 212 bytes

_heapbase

0 0

1 0

2 0

3 0

4 0

5 0

6 0

7 0

8 0

9 0

10 0

11 0

_fragblocks

0 next prev

1 0 0

2 0 0

3 0 0

4 0 0

5 0 0

6 0 0

7 0 0

8 0 0

9 0 0

10 0 0

11 0 0

_fraghead_heapinfo[0]

_heapinfo[1]

_heapinfo[210-1]

0

12

24

Page 38: Heap Management

_heapbase = (char *) _heapinfo;

HEAP = 222 bytes

BLOCKSIZE

= 212 bytes

_heapbase

0 0

1 0

2 0

3 0

4 0

5 0

6 0

7 0

8 0

9 0

10 0

11 0

_fragblocks

0 next prev

1 0 0

2 0 0

3 0 0

4 0 0

5 0 0

6 0 0

7 0 0

8 0 0

9 0 0

10 0 0

11 0 0

_fraghead_heapinfo[0]

_heapinfo[1]

_heapinfo[210-1]

0

12

24

Page 39: Heap Management

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?

Page 40: Heap Management

136: --size;137: for (log=1; (size>>=1)!=0; ++log)

• At the end the following will be true:• 2log >= size > 2log-1

• For example:• size = 80• in binary size = 1010000• --size = 1001111• log = 7

• Why --size?

Page 41: Heap Management

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…)

Page 42: Heap Management

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

Page 43: Heap Management

184: blocks = BLOCKIFY(size)

• We get the number of blocks this size corresponds to.

• In our case:– size = 4096– blocks = 1

Page 44: Heap Management

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

Page 45: Heap Management

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.

Page 46: Heap Management

line 193 -- 203

Suppose we need 4 more blocks

_heapinfo[0]

_heapinfo[1]

_heapinfo[210-1]

4th block

5st block

6nd block

7rd block

_heapinfo[0]

_heapinfo[1]

_heapinfo[210-1]

4th block

5st block

6nd block

7rd block

8th block

9th block

We just need to ask for 2 more.

Page 47: Heap Management

204: result = morecore(blocks * BLOCKSIZE)

_heapbase

0 0

1 0

2 0

3 0

4 0

5 0

6 0

7 0

8 0

9 0

10 0

11 0

_fragblocks

0 next prev

1 0 0

2 0 0

3 0 0

4 0 0

5 0 0

6 0 0

7 0 0

8 0 0

9 0 0

10 0 0

11 0 0

_fraghead_heapinfo[0]

_heapinfo[1]

_heapinfo[210-1]

1st Block

0

12

24

result

Page 48: Heap Management

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.

Page 49: Heap Management

Line 164 -171

0NEXT PREV

31 frags

each frag has 128 bytes

1st block

0 next prev

1 0 0

2 0 0

3 0 0

4 0 0

5 0 0

6 0 0

7 0

8 0 0

9 0 0

10 0 0

11 0 0

_fraghead

NEXT PREV

NEXT PREV

NEXT PREV

NEXT PREV

0

Page 50: Heap Management

Line 174 - 177

• Fill in _heapinfo.

• Return the result.

• Done!