Memory Allocation Alan L Cox alcrice edu Objectives
Memory Allocation Alan L. Cox alc@rice. edu
Objectives Be able to describe the differences between static and dynamic memory allocation Be able to use malloc() and free() to manage dynamically allocated memory in your programs Be able to analyze programs for memory management related bugs Cox Memory Allocation 2
Big Picture C gives you access to underlying data representations & layout w Needed for systems programming w Potentially dangerous for application programming w Necessary to understand Memory is a finite sequence of fixed-size storage cells w Most machines view storage cells as bytes • “byte-addresses” • Individual bits are not addressable w May also view storage cells as words Cox Memory Allocation 3
Structure Representation & Size sizeof(struct …) = sum of sizeof(field) + struct Char. Int { char c 1; char c 2; int i; } foo; alignment padding Processor- and compiler-specific foo. c 1 = ’a’; foo. c 2 = ’b’; foo. i = 0 x. DEADBEEF; c 1 c 2 61 62 padding i EF BE AD DE x 86 uses “little-endian” representation Cox Structures and Unions 4
Pointer Arithmetic pointer + number E. g. , pointer + 1 char pointer – number adds 1 something to a pointer *p; a; b; p = &a; p += 1; int int In each, p now points to b (Assuming compiler doesn’t reorder variables in memory) Adds 1*sizeof(char) to the memory address *p; a; b; p = &a; p += 1; Adds 1*sizeof(int) to the memory address Pointer arithmetic should be used cautiously Cox Arrays and Pointers 5
Can you tell if there is padding? Yes! Print the addresses of foo. c 2 and foo. i Cox c 1 c 2 61 62 struct Char. Int { char c 1; char c 2; int i; } foo; …(code from before)… printf(“&foo. c 2 = %pn”, &foo. c 2); printf(“&foo. i = %pn”, &foo. i); padding i EF Memory Allocation BE AD DE 6
Can you access the padding? Yes! struct Char. Int { char c 1; char c 2; int i; } foo; …(code from before)… char *cp = &foo. c 2; cp += 1; *cp = 0 x 7 F; c 1 c 2 61 62 padding 7 F i EF BE AD DE x 86 uses “little-endian” representation Cox Memory Allocation 7
Can you access both bytes? Yes! struct Char. Int { char c 1; char c 2; int i; } foo; …(code from before)… short *sp = (short *)(&foo. c 2 + 1); *sp = 0 x 7 FFF; c 1 c 2 61 62 padding FF i 7 F EF BE AD DE x 86 uses “little-endian” representation Cox Memory Allocation 8
A Running Program’s Memory 0 x 7 FFFFFF Unused Created at runtime User Stack 47 bits of address space Shared Libraries Shared among processes Created at runtime Heap Read/Write Data Read-only Code and Data Loaded from the executable Unused 0 x 000000 Cox Memory Allocation 9
Allocation For all data, memory must be allocated w Allocated = memory space reserved Two questions: w When do we know the size to allocate? w When do we allocate? Two possible answers for each: w Compile-time (static) w Run-time (dynamic) Cox Memory Allocation 10
How much memory to allocate? Sometimes obvious: char int c; array[10]; One byte 10 * sizeof(int) (= 40 on CLEAR) Sometimes not: char *c; int *array; Is this going to point to one character or a string? How big will this array be? w How will these be used? ? ? • Will they point to already allocated memory (what we’ve seen so far)? • Will new memory need to be allocated (we haven’t seen this yet)? Cox Memory Allocation 11
malloc() Won’t continually remind you of this #include <stdlib. h> int *array = malloc(num_items * sizeof(int)); Allocate memory dynamically w Pass a size (number of bytes to allocate) • Finds unused memory that is large enough to hold the specified number of bytes and reserves it w Returns a void * that points to the allocated memory • No typecast is needed for pointer assignment w Essentially equivalent to new in Java (and C++) Cox Memory Allocation 12
Using malloc() int *i; int *array; Statically or dynamically allocates space for 2 pointers i = malloc(sizeof(int)); array = malloc(num_items * sizeof(int)); Dynamically allocates space for data *i = 3; array[3] = 5; i and array are interchangeable w Arrays pointers to the initial (0 th) array element w i could point to an array, as well w May change over the course of the program Allocated memory is not initialized! w calloc zeroes allocated memory (otherwise, same as malloc; details to come in lab) Cox Memory Allocation 13
Using malloc() Always check the return value of library calls like malloc() for errors int *a = malloc(num_items * sizeof(int)); if (a == NULL) { fprintf(stderr, “Out of memory. n”); exit(1); } Terminate now! And, indicate error. w For brevity, won’t in class • Lab examples and provided code for assignments will w Textbook uses capitalization convention • Capitalized version of functions are wrappers that check for errors and exit if they occur (i. e. Malloc) • May not be appropriate to always exit on a malloc error, though, as you may be able to recover memory Cox Memory Allocation 14
When to Allocate? Static time Dynamic time w Typically global w Typically local variables: int f(…) { int value; … } int main(void) { … } int value; int main(void) { … } w Only one copy ever exists, so can allocate at compile-time Cox w One copy exists for each Memory Allocation call – may be unbounded # of calls, so can’t allocate at compile-time 15
When to Allocate? Static time w Some local variables: One copy exists for all calls – allocated at compile-time Cox int f(…) { static int value; … } int main(void) { … } Memory Allocation Confusingly, local static has nothing to do with global static! 16
Allocation in Process Memory 0 x 7 FFFFFF Static size, dynamic allocation Stack Local variables Shared Libraries Programmer controlled (variable-sized objects) Dynamic size, dynamic allocation Heap Read/Write Data Static size, static allocation Read-only Code and Data Global variables (and static local variables) 0 x 000000 Cox Memory Allocation 17
Why are there different methods? Heap allocation is the most general w Supports any size and number of allocations Why don’t we use it for everything? w Performance Static allocation takes no run time Stack allocation takes orders of magnitude less run time than heap allocation Cox Memory Allocation 18
Deallocation Space allocated via variable definition (entering scope) is automatically deallocated when exiting scope … f(void) { int y; int array[10]; … } w Can’t refer to y or array outside of f(), so their space is deallocated upon return Cox Memory Allocation 19
Deallocation malloc() allocates memory explicitly w Must also deallocate it explicitly (using free())! w Not automatically deallocated (garbage collected) as in Python and Java w Forgetting to deallocate leads to memory leaks & running out of memory int *a = malloc(num_items * sizeof(int)); … free(a); … a = malloc(2 * num_items * sizeof(int)); Must not use a freed pointer unless reassigned or reallocated Cox Memory Allocation 20
Deallocation Space allocated by malloc() is freed when the program terminates w If data structure is used until program termination, don’t need to free w Entire process’ memory is deallocated Cox Memory Allocation 21
Back to create_date Date * create_date 3(int month, int day, int year) { Date *d; d->month = month; d->day = day; d->year = year; d = malloc(sizeof(Date)); if (d != NULL) { d->month = month; d->day = day; d->year = year; } return (d); } Cox Memory Allocation 22
Pitfall void foo(void) { Date *today; Potential problem: memory allocation is performed in this function (may not know its implementation) today = create_date 3(1, 28, 2020); /* Use “today”, if it is not NULL. */. . . return; } Memory is still allocated for “today”! Will never be deallocated (calling function doesn’t even know about it) Cox Memory Allocation 23
Possible Solutions void foo(void) { Date *today; today = create_date 3(…); /* Use “today”, … */. . . free(today); return; destroy_date(today); return; } } Explicitly deallocate memory – specification of create_date 3 must tell you to do this Cox Complete the abstraction – “create” has a corresponding “destroy” Memory Allocation 24
Common Memory Management Mistakes Cox Memory Allocation 25
What’s Wrong With This Code? int *f(…) { int i; … return (&i); } int *make_array(…) { int array[10]; … return (array); } Consider the statement j = *f(); Leads to referencing deallocated memory w Never return a pointer to a local variable! Behavior depends on allocation pattern w Space not reallocated (unlikely) works w Space reallocated very unpredictable Cox Memory Allocation 26
One Solution int *f(…) { int *i_ptr = malloc(sizeof(int)); … return (i_ptr); } int *make_array(…) { int *array = malloc(10 * sizeof(int)); … return (array); } Allocate with malloc(), and return the pointer w Upon return, space for local pointer variable is deallocated w But the malloc-ed space isn’t deallocated until it is free-d w Potential memory leak if caller is not careful, as with create_date 3… Cox Memory Allocation 27
What’s Wrong With This Code? Initialization loop for y[] i=0 j=0 /* Return “y = Ax”. */ int *matvec(int **A, int *x) { int *y = malloc(N * sizeof(int)); int i, j; for (; i<N; i+=1) for (; j<N; j+=1) y[i] += A[i][j] * x[j]; return (y); } malloc-ed & declared space is not initialized! w i, j, y[i] initially contain unknown data – garbage w Often has zero value, leading to seemingly correct results Cox Memory Allocation 28
What’s Wrong With This Code? char **p; int i; /* Allocate space for M*N matrix. */ p = malloc(M * sizeof(char)); char * for (i = 0; i < M; i++) p[i] = malloc(N * sizeof(char)); Allocates wrong amount of memory w Leads to writing into either unallocated memory or memory allocated for something else Cox Memory Allocation 29
Quiet Please! It’s time to start … Cox Memory Allocation 30
Explanation Heap region in memory (each rectangle represents one byte) Assume M = N = 2, a memory address is 8 bytes (or 64 bits) ` for (i = 0; i < M; i++) p[i] = malloc(N * sizeof(char)); p[0] p = malloc(M * sizeof(char)); Cox Memory Allocation 31
Corrected code Heap region in memory (each rectangle represents one byte) Assume M = N = 2, a memory address is 8 bytes (or 64 bits) for (i = 0; i < M; i++) p[i] = malloc(N * sizeof(char)); ` p[1] p[0] p = malloc(M * sizeof(char *)); Cox Memory Allocation 32
What’s Wrong With This Code? char **p; int i; < /* Allocate space for M*N matrix. */ p = malloc(M * sizeof(char *)); for (i = 0; i <= M; i += 1) p[i] = malloc(N * sizeof(char)); Off-by-1 error w Uses interval 0…M instead of 0…M-1 w Leads to writing unallocated memory Be careful with loop bounds! Cox Memory Allocation 33
Using const with pointers const int *iptr w Pointer to a constant integer w Cannot write to *iptr int *const iptr w Constant pointer to an integer w Cannot modify the pointer (iptr) w Can write to *iptr char * xyz(char * to, const char * from) { char *save = to; for (; (*to = *from); ++from, ++to); return(save); } Cox Memory Allocation 34
What’s Wrong With This Code? char *s = “ 1234567”; … char t[7]; strcpy(t, s); char * strcpy(char * to, const char * from) { char *save = to; for (; (*to = *from); ++from, ++to); return(save); } t[] doesn’t have space for string terminator w Leads to writing into unallocated memory One way to avoid: char *s = “ 1234567”; … char *t = malloc((strlen(s) + 1) * sizeof(char)); strcpy(t, s); Cox Memory Allocation 35
What’s Wrong With This Code? /* * Search memory for a value. * Assume value is present. */ int *search(int *p, int value) { while (*p > 0 && *p != value) p += sizeof(int); return (p); } p += 1; Misused pointer arithmetic w Search skips some data, can read unallocated memory, and might not ever see value w Should never add sizeof() to a pointer w Could consider rewriting this function & its uses to use array notation instead Cox Memory Allocation 36
What’s Wrong With This Code? x = malloc(N * sizeof(int)); … free(x); … y = malloc(M * sizeof(int)); for (i = 0; i < M; i++) { y[i] = x[i]; x[i] += 1; } Premature free() w Reads and writes deallocated memory Behavior depends on allocation pattern w Space not reallocated works w Space reallocated very unpredictable Cox Memory Allocation 37
What’s Wrong With This Code? free(x); void foo(void) { int *x = malloc(N * sizeof(int)); … return; } Memory leak – doesn’t free malloc-ed space w Data still allocated, but inaccessible, since can’t refer to x Initially slows future memory performance and may ultimately lead to failure Cox Memory Allocation 38
What’s Wrong With This Code? struct ACons { int first; struct ACons *rest; }; typedef struct ACons *List; A peek at one way to define lists List cons(int first, List rest) { List item = malloc(sizeof(struct ACons)); item->first = first; item->rest = rest; return (item); } void foo(void) { List list = cons(1, cons(2, cons(3, NULL))); … free(list); return; } Cox Memory Allocation 39
Example continued Memory leak – frees only beginning of data structure w Remainder of data structure is still allocated, but inaccessible w Need to write deallocation (destructor) routines for each data structure Cox Memory Allocation 40
Putting it all together. . . bools strings pointers structs malloc() calls simple I/O simple string operations Cox Memory Allocation 41
What does action 1() do? struct thing { char *stuff; struct thing *another_thing; }; #include <stdio. h> #include <stdlib. h> #include <string. h> void action 1(struct thing **yp, const char *stuff) { struct thing *x = malloc(sizeof(struct thing)); /* Alternatively, x->stuff = strdup(stuff); */ x->stuff = malloc(strlen(stuff) + 1); strcpy(x->stuff, stuff); x->another_thing = *yp; *yp = x; } int main(void) { struct thing *y = NULL; action 1() inserts a new node storing the specified string into the linked list action 1(&y, "Cox"); Cox Memory Allocation 42
What does action 2() do? struct thing { char *stuff; struct thing *another_thing; }; void action 2(struct thing **yp) { struct thing *x; while ((x = *yp) != NULL) { printf("%s ", x->stuff); yp = &x->another_thing; } putchar('n'); } int main(void) { struct thing *y = NULL; . . . action 2(&y); action 2() prints the strings stored in the linked list nodes sequentially Cox Memory Allocation 43
What does action 3() do? struct thing { char *stuff; struct thing *another_thing; }; bool action 3(struct thing **yp, const char *stuff) { struct thing *x; while ((x = *yp) != NULL) { if (strcmp(x->stuff, stuff) == 0) return (true); else yp = &x->another_thing; } return (false); } int main(void) { struct thing *y = NULL; . . . action 3(&y, "Cox"); action 3() finds out whether a string is stored in the linked list Cox Memory Allocation 44
What does action 4() do? struct thing { char *stuff; struct thing *another_thing; }; void action 4(struct thing **yp, const char *stuff) { struct thing *x; while ((x = *yp) != NULL) { if (strcmp(x->stuff, stuff) == 0) { *yp = x->another_thing; free(x->stuff); free(x); return; } else yp = &x->another_thing; } } int main(void) { struct thing *y = NULL; . . . action 4(&y, "Cox"); style list compromised to action 4() deletes the first node that save space stores the specified string Cox Memory Allocation 45
Next Time Lab: Debugging Assembly Cox Memory Allocation 46
Assembly Language Alan L. Cox alc@rice. edu Some slides adapted from CMU 15. 213 slides
Objectives Be able to read simple x 86 -64 assembly language programs Cox Assembly 48
Why Learn Assembly Language? You’ll probably never write a complete program in assembly w With a few exceptions, modern compilers are much better at writing assembly than you are But, understanding assembly is key to understanding the machine-level execution model w Behavior of programs in presence of bugs • High-level language model breaks down w Tuning program performance • Understanding sources of program inefficiency w Implementing system software • Compiler has machine code as target • Operating systems must manage process state Cox Assembly 49
Assembly Language One assembly instruction w Straightforward translation to a group of machine language bits that describe one instruction What do these instructions do? w Same kinds of things as high-level languages! • Arithmetic & logic – Core computation • Data transfer – Copying data between memory locations and/or registers • Control transfer – Changing which instruction is next Cox Assembly 50
Assembly Language (cont. ) But, assembly language has additional features: w Distinguishes instructions & data w Labels = names for program control points w Pseudo-instructions = special directives to the assembler w Macros = user-definable abbreviations for code & constants Cox Assembly 51
- Slides: 51