0% found this document useful (0 votes)
17 views

06-memory-allocation

Uploaded by

ahktanov.a
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views

06-memory-allocation

Uploaded by

ahktanov.a
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 56

Carnegie Mellon

Memory Allocation
COMP 222: Introduction to Computer Organization

Instructor:
Alan L. Cox

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 1


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

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 2


Big Picture
 C gives you access to underlying data
representations & layout
 Needed for systems programming
 Potentially dangerous for application programming
 Necessary to understand
 Memory is a finite sequence of fixed-size storage
cells
 Most machines implement byte-sized storage cells

“byte-addresses”
 Individual bits are not addressable
 May also access multiple, aligned, contiguous storage cells as words, half-
words, quarter-words, etc.

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 3


Structure Representation &
Size
sizeof(struct …) =
sum of sizeof(field) struct CharCharInt {
char c1;
+ alignment padding
Processor- and compiler-specific
char c2;
int i;
} foo;

foo.c1 = ’a’;
foo.c2 = ’b’;
foo.i = 0xDEADBEEF;

c1 c2 padding i

61 62 EF BE AD DE
x86 uses “little-endian” representation

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 4


Pointer Arithmetic
pointer + number pointer – number

E.g., pointer + 1 adds 1 something to a pointer

char *p; int *p;


char a; int a;
char b; int b;

p = &a; p = &a;
p += 1; In each, p now points to b p += 1;
(Assuming compiler doesn’t
reorder variables in memory)

Adds 1*sizeof(char) to Adds 1*sizeof(int) to


the memory address the memory address

Pointer arithmetic should be used cautiously

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 5


Can you tell if there is padding?
Yes! struct CharCharInt {
char c1;
char c2;
int i;
Print the } foo;

addresses of …(code from before)…

foo.c2 and printf(“&foo.c2 = %p\n”, &foo.c2);


foo.i printf(“&foo.i = %p\n”, &foo.i);

c1 c2 padding i

61 62 EF BE AD DE

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 6


Can you access the padding?
struct CharCharInt {
Yes! char c1;
char c2;
int i;
} foo;

…(code from before)…

char *cp = &foo.c2;


cp += 1;
*cp = 0x7F;

c1 c2 padding i

61 62 7F EF BE AD DE
x86 uses “little-endian” representation

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 7


Can you access both bytes?
Yes! struct CharCharInt {
char c1;
char c2;
int i;
} foo;

…(code from before)…

short *sp = (short *)(&foo.c2 + 1);


*sp = 0x7FFF;

c1 c2 padding i

61 62 FF 7F EF BE AD DE
x86 uses “little-endian” representation

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 8


A Running Program’s Memory
0x7FFFFFFFFFFF
Unused

User Stack Created at runtime


47 bits of address space

Shared Libraries Shared among processes

Heap Created at runtime

Read/Write Data
Loaded from the executable
Read-only Code and Data

Unused
0x000000000000

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 9


Allocation
 For all data, memory must be allocated
 Allocated = memory space reserved

 Two questions:
 When do we know the size to allocate?
 When do we allocate?
 Two possible answers for each:
 Compile-time (static)
 Run-time (dynamic)

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 10


How much memory to allocate?
 Sometimes obvious:

char c; One byte


int array[10];
10 * sizeof(int) (= 40 on CLEAR)

 Sometimes not:
Is this going to point to one
char *c; character or a string?
int *array;
How big will this array be?

 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)?

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 11


malloc()
Won’t continually
remind you of this

#include <stdlib.h>

int *array = malloc(num_items * sizeof(int));

 Allocate memory dynamically


 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
 Returns a void * that points to the allocated memory
 No typecast is needed for pointer assignment
 Essentially equivalent to new in Java

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 12


Using malloc()
int *i; Statically or
dynamically
int *array;
allocates space for Dynamically
2 pointers allocates
i = malloc(sizeof(int)); space for
array = malloc(num_items * sizeof(int)); data

*i = 3;
array[3] = 5;

 i and array are interchangeable


 Arrays  pointers to the initial (0th) array element
 i could point to an array, as well
 May change over the course of the program
 Allocated memory is not initialized!
 calloc zeroes allocated memory (otherwise, same as malloc; details to
come in practice lab)

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 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.
 For brevity, won’t in class
 Lab examples and provided code for assignments will
 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

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 14


When to Allocate?

 Static
Dynamic time time
 Typically
Typically global variables:
local variables:
int f(…)
{
int value;
int value;
int main(void)

{
}

int main(void)
}
{

}
 Only one copy ever exists, so can allocate at compile-time
 One copy exists for each call – may be unbounded # of calls, so can’t allocate at
compile-time

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 15


When to Allocate?
 Static time
 Some local variables:
int f(…)
{
static int value;

One copy exists }
for all calls – int main(void)
allocated at {
compile-time
… Confusingly, local
} static has nothing to
do with global static!

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 16


Allocation in Process Memory
0x7FFFFFFFFFFF

Stack Static size, dynamic allocation


Local variables

Shared Libraries

Programmer controlled
(variable-sized objects)
Heap Dynamic size, dynamic allocation

Read/Write Data Static size, static allocation

Read-only Code and Data Global variables


(and static local variables)

0x000000000000

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 17


Why are there different
methods?
 Heap allocation is the most general
 Supports any size and number of allocations

 Why don’t we use it for everything?


 Performance

 Static allocation takes no run time

 Stack allocation takes orders of magnitude less run


time than heap allocation

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 18


Deallocation
 Space allocated via variable definition (entering
scope) is automatically deallocated when exiting
scope
… f(void)
{
int y;
int array[10];

}

 Can’t refer to y or array outside of f(), so their space is deallocated


upon return

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 19


Deallocation
 malloc() allocates memory explicitly
 Must also deallocate it explicitly (using free())!
 Not automatically deallocated (garbage collected) as in Python and Java
 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

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 20


Deallocation
 Space allocated by malloc() is freed when the
program terminates
 If data structure is used until program termination, don’t need to free
 Entire process’ memory is deallocated

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 21


Back to create_date
Date * Date *
create_date3(int month, create_date3(int month,
int day, int year) int day, int year)
{ {
Date *d; Date *d;

d->month = month; d = malloc(sizeof(Date));


d->day = day; if (d != NULL) {
d->year = year; d->month = month;
d->day = day;
return (d); d->year = year;
} }

return (d);
}

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 22


Pitfall
void
foo(void) Potential problem:
{ memory allocation is
Date *today; performed in this
function (may not know
today = create_date3(9, 20, 2024); its implementation)

/* 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)
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 23
Possible Solutions
void void
foo(void) foo(void)
{ {
Date *today; Date *today;

today = create_date3(…); today = create_date3(…);

/* Use “today”, … */ /* Use “today”, … */


... ...

free(today); destroy_date(today);
return; return;
} }

Explicitly deallocate Complete the abstraction –


memory – specification of “create” has a corresponding
create_date3 must tell you “destroy”
to do this
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 24
Scenario
 Suppose that we want to maintain a collection of
integers, but ...
 Over time, we will both add integers to and remove integers from the
collection
 And, we don't know the maximum size of the collection in advance

 We could use an array, but …


 For example, what happens when the size of the collection grows to the
point that it exceeds the array size?

 What are the alternatives?

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 25


Linked List
 A linked list of integers has a naturally recursive
definition:
A linked list of integers is ...
 either empty, represented by NULL, or …
 non-empty, represented by a pointer to a struct with a first and a rest,
where …
 first is an integer and …
 rest is a pointer to a linked list
struct list {
int first;
struct list *rest;
};

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 26


Make Non-Empty
struct list {
int first;
struct list *rest;
};

struct list *makeNE(int first, struct list *rest)


{
struct list *item = Malloc(sizeof(struct list));
item->first = first;
item->rest = rest;
return (item);
}

void foo(void)
{
struct list *list = makeNE(1, makeNE(2, makeNE(3, NULL)));
...

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 27


What's Wrong With This
makeNE?
struct list {
int first;
struct list *rest;
};

struct list *makeNE(int first, struct list *rest)


{
struct list item;
item.first = first;
item.rest = rest;
return (&item);
}

void foo(void)
{
struct list *list = makeNE(1, makeNE(2, makeNE(3, NULL)));
...

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 28


Visualization

list:

1 pad

2 pad

3 pad NULL

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 29


Recursive Traversal
struct list {
int first;
struct list *rest;
};

void recur_print(struct list *list)


{
if (list == NULL) {
printf("NULL\n");
} else {
printf("%d, ", list->first);
recur_print(list->rest);
}
}

void foo(void)
{
struct list *list = makeNE(1, makeNE(2, makeNE(3, NULL)));
recur_print(list);
...

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 30


Iterative Traversal
struct list {
int first;
struct list *rest;
};

void iter_print(struct list *list)


{
while (list != NULL) {
printf("%d, ", list->first);
list = list->rest;
}
printf("NULL\n");
}

void foo(void)
{
struct list *list = makeNE(1, makeNE(2, makeNE(3, NULL)));
iter_print(list);
...

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 31


Iterative Append
struct list {
int first;
struct list *rest;
};

struct list *iter_append(struct list *list, int last_int)


{
struct list *last = makeNE(last_int, NULL);
if (list == NULL)
return (last);
struct list *curr = list;
while (curr->rest != NULL) // Find the last non-empty.
curr = curr->rest;
curr->rest = last;
return (list);
}

void foo(void)
{
struct list *list = makeNE(1, makeNE(2, makeNE(3, NULL)));
list = iter_append(list, 4);
...
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 32
Removal
struct list {
int first;
struct list *rest;
};

void foo(void)
{
struct list *list = makeNE(1, makeNE(2, makeNE(3, NULL)));

// Remove 2 from the list:


struct list *two = list->rest;
list->rest = two->rest;
free(two);

...
}

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 33


Assignment to two

list:

1 pad

2 pad

two:
3 pad NULL

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 34


Assignment to list->rest

list:

1 pad

2 pad

two:
3 pad NULL

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 35


free(two)

list:

1 pad

two:
3 pad NULL

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 36


Common Memory Management Mistakes

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 37


What’s Wrong With This Code?
int *f(…) int *make_array(…)
{ {
int i; int array[10];
… …
return (&i); return (array);
} }

 Consider the statement j = *f();

 Leads to referencing deallocated memory


 Never return a pointer to a local variable!

 Behavior depends on allocation pattern


 Space not reallocated (unlikely)  works
 Space reallocated  very unpredictable

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 38


One Solution
int *f(…) int *make_array(…)
{ {
int *i_ptr = int *array =
malloc(sizeof(int)); malloc(10 * sizeof(int));
… …
return (i_ptr); return (array);
} }

 Allocate with malloc(), and return the pointer


 Upon return, space for local pointer variable is deallocated
 But the malloc-ed space isn’t deallocated until it is free-d
 Potential memory leak if caller is not careful, as with create_date3…

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 39


What’s Wrong With This Code?
/* Return “y = Ax”. */
int *matvec(int **A, int *x) {
int *y = malloc(N * sizeof(int));
Initializatio int i, j;
n loop for
i=0y[] for (; i<N; i+=1)
j=0 for (; j<N; j+=1)
y[i] += A[i][j] * x[j];
return (y);
}

 malloc-ed & declared space is not initialized!


 i, j, y[i] initially contain unknown data – garbage
 Often has zero value, leading to seemingly correct results

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 40


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


 Leads to writing into either unallocated memory or memory allocated for
something else

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 41


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

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 42


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 *));

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 43


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
 Uses interval 0…M instead of 0…M-1
 Leads to writing unallocated memory

 Be careful with loop bounds!

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 44


Using const with pointers
 const int *iptr
 Pointer to a constant integer
 Cannot write to *iptr

 int *const iptr


 Constant pointer to an integer
 Cannot modify the pointer (iptr)
 Can write to *iptr
char *
xyz(char * to, const char * from)
{
char *save = to;
for (; (*to = *from); ++from, ++to);
return(save);
}

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 45


What’s Wrong With This Code?
char *s = “1234567”; char *
… strcpy(char * to, const char * from)
char t[7]; {
strcpy(t, s); char *save = to;
for (; (*to = *from); ++from, ++to);
return(save);
}

 t[] doesn’t have space for string terminator


 Leads to writing into unallocated memory
 One way to avoid:

char *s = “1234567”;

char *t = malloc((strlen(s) + 1) * sizeof(char));
strcpy(t, s);

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 46


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); p += 1;
return (p);
}

 Misused pointer arithmetic


 Search skips some data, can read unallocated memory, and might not
ever see value
 Should never add sizeof() to a pointer
 Could consider rewriting this function & its uses to use array notation
instead

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 47


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()
 Reads and writes deallocated memory

 Behavior depends on allocation pattern


 Space not reallocated  works
 Space reallocated  very unpredictable

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 48


What’s Wrong With This Code?
void foo(void) {
int *x = malloc(N * sizeof(int));

free(x);
return;
}

 Memory leak – doesn’t free malloc-ed space


 Data still allocated, but inaccessible, since can’t refer to x

 Initially slows future memory performance and


may ultimately lead to failure

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 49


What's Wrong With This Code?
struct list {
int first;
struct list *rest;
};

struct list *makeNE(int first, struct list *rest)


{
struct list *item = Malloc(sizeof(struct list));
item->first = first;
item->rest = rest;
return (item);
}

void foo(void)
{
struct list *list = makeNE(1, makeNE(2, makeNE(3, NULL)));
...
free(list);

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 50


Example continued

Memory leak – frees only beginning of data structure


 Remainder of data structure is still allocated, but
inaccessible
 Need to write deallocation (destructor) routines for each
data structure

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 51


Putting it all together ...
 bools
 strings

 pointers

 structs

 malloc() calls

 simple I/O

 simple string operations

Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 52


What does action1() do?
struct thing {
#include <stdio.h>
char *stuff;

struct thing *another_thing;

}; #include <stdlib.h>

void
#include <string.h>
action1(struct thing **yp, const char *stuff)

struct thing *x = malloc(sizeof(struct thing));

action1() inserts a new node storing the specified


/* Alternatively, x->stuff = strdup(stuff); */
string into the linked list
x->stuff = malloc(strlen(stuff) + 1);

strcpy(x->stuff, stuff);
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 53
What does action2() do?
struct thing {

char *stuff;

struct thing *another_thing;

};

void

action2(struct thing **yp)

struct thing *x;

action2() prints the strings stored in the


while ((x = *yp) != NULL) {
linked list nodes sequentially
printf("%s ", x->stuff);

yp = &x->another_thing;
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 54
What does action3() do?
struct thing {

char *stuff;

struct thing *another_thing;

};

bool

action3(struct thing **yp, const char *stuff)

struct thing *x;


while ((x = *yp) != NULL) {

action3() finds out whether a string


if (strcmp(x->stuff, stuff) == 0)

is stored in the linked list


return (true);

else

yp = &x->another_thing;
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 55
What does action4() do?
struct thing {

char *stuff;

struct thing *another_thing;

};

void

action4(struct thing **yp, const char *stuff)

struct thing *x;

action4() deletes the first list node that


while ((x = *yp) != NULL) {
stores the specified string
if (strcmp(x->stuff, stuff) == 0) {

*yp = x->another_thing;
Bryant and O’Hallaron, Computer Systems: A Programmer’s Perspective, Third Edition 56

You might also like