1 Lecture 5 - Memory Layout and Allocation 2 Rationale You have learnt how to grab memory using malloc() and free(). why we need to study different.

Post on 19-Dec-2015

220 Views

Category:

Documents

2 Downloads

Preview:

Click to see full reader

Transcript

1

Lecture 5 - Memory Layout and Allocation

2

Rationale

You have learnt how to grab memory using malloc() and free(). why we need to study different memory management?

We use malloc(10) to grab 10 bytes, what happens if we use memory more than 10 bytes? Will we overwrite the memory?

How to know that the memory is 10 bytes, where we can store the information?

3

Topics

Heap Allocation – tweak and buddy systems Memory Bug

Review of Pointers in C

Making and Using Bad References

Overwriting Memory

Twice free

Memory Leaks

Exterminating Memory Bugs

Garbage Collection

4

Details on Simple Algorithm

Block Sizes Finding Free Blocks Splitting a Free Block Finding a Suitable Block Coalescing Free Blocks (means merge) Searching for Free Blocks (three methods,

best, first and worst fits)

5

Block sizes – the size to hold the data for users’ usage

The standard method for determining the size of a block, given a pointer to the block, is to store its size in the word before the pointer.

Here, the memory block that can be used is 16 bytes, the block size is 20 bytes including 4 bytes for the size

Only 16

bytes

6

Determine the size Note that it uses [-1] to

point to location before the pointer (location that contains block size)

As the size is a multiple of 4, it clears the lowest two bits (3 =0000 0000 0000 0011 (hex), ~3 = 1111 1111 1111 1100

Free means the block can be used by user (binary 1)

size = ((int *) ptr)[-1]; // read integer before the memory block

correct_size = size & ~3; // clear the lower 2 bits

free = size & 1; // get low-order bit

7

How to determine whether the block is free or allocated

Assume that the block size is a multiple of 4, the lowest two bits are zero.

We can use the lowest bit (least significant) to indicate whether the block is free (binary 1) or allocated (binary 0)

8

How to find the free blocks If we keep a size word for

both free blocks and allocated blocks, we can skip from block to block by adding the size to the current block address to get the next block address.

Assume the pointer is pointing to the first block (allocated 12), we can then determine the address of next block (20 free)

Address ptr += 12;

9

Small program pointer first points to

heap_begin (note that heap_begin[200] =“…”; the address is heap_begin

Get the size by masking the lowest two bits (note *(int *))

The next address is then obtained by ptr = ptr + size; (or ptr += size)

char *ptr = heap_begin; // get pointer to first block

while (ptr < heap_end) {

size = *((int *) ptr);

size &= ~3; // mask off low order bits

ptr += size; // increment pointer to next block

}

10

Splitting a Free Block The heap is normally initialized to

look like one giant free block. (40 bytes)

When allocations occur, it would be wasteful to return a large block of free memory when a small one would do just as well. (I need 8 bytes, no point to return 40 bytes)

Therefore, the memory allocator will typically split a block if the block size is larger than the requested size. (12 allocated and 28 free)

11

Finding a suitable block There are at least three methods Best fit, search all the blocks and find one that is

free and the size perfectly matches the requirements (I need 20, it returns 20.)

First fit, search all the blocks and return the first one that is free and fulfill the requirements (I need 20, the first one is 30.)

Worst fit, find the largest one that is free and splits it. (The largest is 80, I need 20. It splits this into 20 and 60. I take 20 and leaves 60 in the heap)

12

Coalescing Free Blocks

Coalescing means to merge all free blocks together

In this example, two free blocks of 16 and 8 are merged together to form a larger free block of 24.

This will reduce fragmentation.

13

Searching for Free Blocks Use free link list to find

free blocks In this diagram, there

are a linked list to point to the next and previous.

The advantage is that it will speed up the operation of finding a free block.

14

Ways to speed up operation

To speed up the operation, we can form a free list (group free blocks together with a linked list) such as the size of 8, 16, 32, 64…)

If we want a block of 20, it can simply return a block of 32. (note that 12 are wasted.)

If we want a block of 28, it can also simply return a block of 32. In this case, 2 are wasted.

15

Memory Bugs

Review of Pointers in C Making and Using Bad References Overwriting Memory Twice free Memory Leaks Exterminating Memory Bugs Garbage Collection

16

Review of Pointers in C

Here, var occupies 4 bytes, *var_pt also occupies 4 bytes

*var_ptr will be allocated with 3 bytes

// take the address of a variable

int var; // declare the variable

int *var_ptr; // declare the pointer

var_ptr = &var; // take the address of var

*var_ptr = 3; // stores 3 into var

// access variable pointed to by var_ptr

if (var == *var_ptr) printf("ok\n");

17

Pointers and integers can be added

Pointer can be added For an integer pointer, adding one means 4 bytes For a char pointer, adding one means one byte

For a double pointer, adding one means 8 bytes

For a structure pointer, adding one means the size of this structure

18

Making and Using Bad References

The pointer is not pointing to the right location or is not properly initalised.

It might cause the program to crash.

Here, *p is not pointing to int a[].

To solve it, P = a;

int sum(int a[], int n)

{

int *p;

int sum = 0;

for (int i = 0; i < n; i++)

sum += *p++;

}

19

Common bug in scanf

Note that you should supply the address rather than the variable

Use &i; instead of i It is important in

your exam.

int i;

double d;

scanf("%d %g", i, d); // wrong!!!

// here is the correct call:

scanf("%d %g", &i, &d);

20

Overwriting Memory

Here, i will be incremented from 0 to array_size, not array_size – 1;

The solution is ; i < array_size;

not ; i <= array_size;

#define array_size 100

int *a = (int *) malloc(sizeof(int *) * array_size);

for (int i = 0; i <= array_size; i++)

a[i] = NULL;

21

Memory bug

Here, the memory allocated is 100 bytes, not 400 bytes and a[] is defined as array pointer

The solution is:

int *a = (int *) malloc( array_size* sizeof(int));

#define array_size 100

int *a = (int *) malloc(array_size);

a[99] = 0; // this overwrites memory beyond the block

22

String must be terminated by 0x00

String must be terminated by 0x00; The solution is:

char *new_s = (char *) malloc(len + 1);

char *heapify_string(char *s)

{ int len = strlen(s);

char *new_s = (char *) malloc(len);

strcpy(new_s, s);

return new_s;

}

By 0x00

23

Operator precedence

Note that *a–- will decrement the pointer not the value.

We should use *(a)-- to refer to the decrement of value

// decrement a if a is greater than zero:

void dec_positive(int *a)

{

*a--; // decrement the integer

if (*a < 0) *a = 0; // make sure a is positive

}

24

Memory bug Although the function

returns a pointer to a zero-valued integer, the integer is in an activation record that is deleted as soon as the function returns

Here, it might return any value once the activation is removed.

int *ptr_to_zero()

{

int i = 0;

return &i;

}

25

Twice free

It means the memory pointer was freed twice.

Here, it free the memory in the routine my_write(), but it is freed in the main

void my_write(x)

{ ... use x ...

free(x); }

int *x = (int *) malloc(sizeof(int*) * N); ...

my_read(x); ...

my_write(x);

free(x); //oops, x is freed in my_write()!

Free the pointer twice

26

Memory leaks

The memory that is on longer used is not returned to the memory pool.

The result is that the system will run out of memory.

The failure to deallocate (free) a block of memory when it is no longer needed is often called a memory leak

Do not return the memory block to

the pool

27

Example

If it is true in the (full_msg), it will not execute to free(full_msg)

It causes memory leak

void my_function(char *msg)

{

// allocate space for a string

char *full_msg = (char *) malloc(strlen(msg) + 100);

strcpy(full_msg, "The following error was encountered: ");

strcat(full_msg, msg);

if (!display(full_msg)) return;

free(full_msg);

}

28

Exterminating Memory Bugs (1)

The file name and line number where the allocation occurred. At the end of execution, any unallocated blocks that might indicate memory leaks can be listed along with the point in the code where the call to malloc() was made.

The status: whether the block is allocated or free. If a block is freed twice, this can usually be detected. The program is stopped immediately, and the debugger is invoked to show from where the extra free() was called.

29

Exterminating Memory Bugs (2)

Padding before and after the block. This padding is filled with a known value such as "0xdeadbeef" so that if memory is overwritten near the boundaries of the block, the changes to the known values can easily be detected.

Links to other blocks. These enable allocated blocks to be scanned and checked.

30

Exterminating Memory Bugs (3)

An allocation sequence number. This helps to identify blocks. Sometimes, you can set a breakpoint to stop when malloc() is about to allocate the block with a given sequence number. This is very useful when you want to figure out where a particular block came from.

31

Garbage Collection One reason there are memory allocation

errors is that memory allocation requires the programmer to obey certain rules:

Allocate memory before using it, free memory eventually but only once, and do not read or write except to allocated memory.

Most of these rules can be automated, eliminating most memory allocation errors. Languages like Lisp, Java, and ML do not require the programmer to free memory, but not C++

32

Example – return of buffer #include <stdio.h> #include <stdlib.h>

void alloc(char* buffer) { printf("Before %p\n",buffer); buffer = (char*)malloc(1000); printf("Allocated :%p\n",buffer); }

int main(void) { char* buffer; printf("Before :%p\n",buffer);

alloc(buffer); printf("After allocation :%p\n",buffer);

return 0; }

Why after allocation, buffer remains cccccccc it means that it is not yet initlised.

It is because, alloc() did not return the buffer.

33

Example – change of return

34

Summary

Free memory when it is not used so that it can be returned to the pool.

Free memory twice will cause error Common bug in scanf, must pass address, not

variable, int a; scanf(&a), not scanf(a)

Reserve one more byte for 0x00

35

More samples - Consider the following C program: #include <string.h>#include <stdio.h> #include <stdlib.h> char* str_upper(char* str) {

char* s = (char*) malloc(str); for (int i = 0; i <= strlen(str); i++) { s[i] = toupper(*str + i);} return s; }

int main(void) { char *str[8] = {"one", "two", "three", "four", "five", "six",

"seven", "eight"}; char* s = NULL; for (int i = 0; i < 8; i++) { s = str_upper(str[i]); printf("%s\n", s); }

free(s); }

36

solution1. malloc size error - The call to malloc in function str_upper allocates an incorrect amount of memory. It should be: malloc(sizeof(char) * (strlen(str) + 1))

2. off by one error - The for-loop in function str_upper is off by one. The condition of the loop needs to be: i < strlen(str)

3. pointer arithmetic- Incorrect pointer arithmetic is used inside the for-loop in function str_upper(). The line should read: s[i] = toupper(*(str+i)); 4. memory leak - Function main has a memory leak. It calls str_upper 8 times (which makes a call to malloc each time), but only frees once. The call to free needs to go inside the for-loop body, after the printf call.

37

More sample – consider the following program

#include <string.h>#include <stdio.h>#include <stdlib.h>void output_reverse(char* s) { for (int i = 0, j = strlen(s); i <= strlen(s); i++, j--) { s[i] = s[j]; } printf("%s\n", s); free(s);} int main(void) { printf("Enter a 100 (or less) character string: \n"); char* str = (char*) malloc(sizeof(char) * 100); scanf("%s", str); output_reverse(str); free(str); return 0;}

38

Solution

1. overwrite memory - The for-loop in output_reverse overwrites memory due to an off by one error in the condition of the loop

2. malloc size error - Function main incorrectly uses malloc. Line should be:

str = (char*) malloc(sizeof(char) * 101); The null terminator must be accounted for.

3. twice free - There are 2 calls to free for one malloc.

39

Sample of program – find out the errors

#include <string.h> #include <stdio.h> #include <stdlib.h> char* copy_reverse(char* str) {

char* s = (char*) malloc(sizeof(str)); for (int i = 0, j = strlen(str); i <= strlen(str); i++, j--) s[i] = str[j]; return &s;

} int main(void) {

char* original = "original string"; char* newstring = NULL; newstring = copy_reverse(&original); fprintf("%s\n", newstring); free(original); free(newstring);

}

40

The solution#include <string.h> #include <stdio.h> #include <stdlib.h> char* copy_reverse(char* str) {

char* s = (char*) malloc(sizeof(char) * (strlen(str) + 1)); for (int i = 0, j = strlen(str); i < strlen(str); i++, j--) s[i] = str[j]; return s;

} int main(void) {

char* original = "original string"; char* newstring = NULL; newstring = copy_reverse(original); fprintf("%s\n", newstring);

// free(original); free(newstring);

}

41

The explanation

1. malloc size error - The call to malloc in function copy_reverse allocates an incorrect amount of memory. It should be: malloc(sizeof(char) * (strlen(str) + 1))

2. off by one error - The for-loop in function copy_reverse will overwrite memory. The condition of the loop needs to be: i < strlen(str)

3. return error - The return call in function copy_reverse returns the address of a local variable. It should return the value of of the pointer. The line should read: return s;

4. passing &char* - Function main makes a call to function copy_reverse, but passes the address of a pointer to type char, instead of a

pointer to type char.

5. free error - There is a call to free made on a non-heap variable in function main. The free(original) needs removed.

top related