L21 DynamicAllocation
L21 DynamicAllocation
Dynamic Storage
Example: We need space to allow the user to enter some data,
but how much?
80 bytes? 132? 1? 256? 10000?
These friends create and manage the heap for us, allowing us
to grab storage at run time
malloc()
struct r {
char name[40]; Stack rp
double gpa;
struct r *next;
};
struct r *rp;
rp = malloc(sizeof(struct r));
Heap
if (rp == NULL){ 56 bytes
/* Handle Error! */
} Data
Options for handling error
Abort
Ask again
Save user data
Code
Ask for less
Free up something
Don’t Do This!
rp = malloc(sizeof struct r);
if(rp == NULL)
Be afraid.
But what is the type of this pointer and how do we use it to store items of a
different type?
malloc() is declared as “void *malloc(unsigned long)”
To be safe, you should cast this pointer into the correct type so that type-
checking can work for you again!
int *ip;
ip = (int *)malloc(sizeof int);
Otherwise, the compiler will silently cast your “void *” pointer into any other
kind of pointer without checking
Done With a Chunk of Storage
When you’re done with a chunk of storage, you use free() to make it
available for reuse.
Remember, C doesn’t do garbage collection
free(rp);
returns the memory back to the heap for re-use by someone else
You must not use the value in rp after the call to free(), nor may you
dereference the memory it points to!
There’s no guarantee what’s at *rp after you call free() – assume it is
garbage data!
With modern C libraries, free(NULL) does nothing but isn’t an error
After free()
From our previous example
free(rp);
Anyone calling this function now has access to ca in this block. Could be
dangerous. Why?
char *pch;
pch = &strDigits[5];
do
return pch;
}
Problem in use
strHighScore =
strFromUnsigned(HighScore);
.
.
.
strThisScore =
strFromUnsigned(ThisScore);
Persistent Data II
char *foo(void)
char ca[10];
return ca;
Since ca was allocated on stack during function call pointer returned is now
pointing to who-knows-what
Bad
Persistent Data III
char *foo(void)
{
char *ca = malloc(...);
/* error checking but no free */
return ca;
}
This actually works, but the caller needs to know that they’re
responsible for the free()
Memory Leaks
Memory leaks occur when the programmer loses track of memory
allocated by malloc or other functions that call malloc
void foo(void)
/* no free */
return;
Bad
Memory Management
Some functions that call malloc
calloc
strdup
regcmp
others...
free After
ptr
realloc: What might happen
ptr After
realloc
Realloc may return
same pointer
different pointer
NULL
cp = realloc(cp, n);
1. Yes
2. No
3. Sometimes
Realloc
Is this a good idea?
cp = realloc(cp, n);
No!
Memory Leak!
How to do it properly
void *tmp;
/* realloc error */
else
O!
N
{
cp = tmp;
free(tmp);
}
Additional Edge Cases
realloc(NULL, n) malloc(n);
We ask the system for big chunks of memory and then split out
small blocks as requested
A. Binary Tree
B. Hash Table
D. Array of Structs
Question
In the K&R implementation of the heap management, free() does the
following:
Consider this:
We want each block in the free list to be as large as possible
So it is more likely to have enough bytes to satisfy a malloc() call
Therefore when we free a block adjacent to our other memory on
the heap, we should merge that block into the adjacent block.
A Node in the Free List
size
size
If the variable
Header *p;
points to the beginning of a block, where does
(char *)p + Headersize
point?
Heap Layout
In In In
use use use
K&R ch. 8
One of those free blocks has user data size 0 and isn’t in the heap,
so it is never handed over by malloc().
Section of K&R Code
static Header base; // empty list to get started with
static Header *freep = NULL; // start of free list
nunits 2 2 2 3 3 4
Section of malloc() Code
if (freep == NULL) {
freep = &base;
base.size = 0;
base.next = &base;
if (morecore(nunits) == NULL)
return NULL; /* none left; give up */
}
0 nunits free
base
next size
freep *
Section of malloc() Code
freep prevp p
In In In
use use use
Section of malloc() Code
if (p->size == nunits)
prevp->next = p->next;
else {
p->size -= nunits;
p = (char *)p + p->size * Headersize;
p->size = nunits;
}
freep = prevp;
return (char *)p + Headersize;
prevp p
p 3 7
10
5 7 5
3
Let nunits = 7, and follow how the free block is identified and returned
Pointer Sent to free()
size
If the variable
char *ap;
points to the address returned to the user, where does
(Header *)((char *)ap – Headersize)
point?
Section of free() Code
void _free(void *ap)
{
Header *bp, *p;
In In In
use use use
Free(): Below and Above In Use
/* Look to see if we're adjacent to the block after the freed block */
if ((char *)bp + bp->size * Headersize == (char *)p->next) {
bp->size += p->next->size;
bp->next = p->next->next;
} else
bp->next = p->next;
/* Look to see if we're adjacent to the block before the freed block */
if ((char *)p + p->size * Headersize == (char *)bp) {
/* add the freed block to the block at p */
p->size += bp->size;
p->next = bp->next;
} else
p->next = bp;
freep = p;
p bp ap p->next
5 3 7 5
Free(): Below In Use
/* Look to see if we're adjacent to the block after the freed block */
if ((char *)bp + bp->size * Headersize == p->next) {
bp->size += p->next->size;
bp->next = p->next->next;
} else
bp->next = p->next;
/* Look to see if we're adjacent to the block before the freed block */
if ((char *)p + p->size * Headersize == bp) {
/* add the freed block to the block at p */
p->size += bp->size;
p->next = bp->next;
} else
p->next = bp;
freep = p;
p
bp ap p->next
10
5
3 7 5
Free(): Above In Use
/* Look to see if we're adjacent to the block after the freed block */
if ((char *)bp + bp->size * Headersize == p->next) {
bp->size += p->next->size;
bp->next = p->next->next;
} else
bp->next = p->next;
/* Look to see if we're adjacent to the block before the freed block */
if ((char *)p + p->size * Headersize == bp) {
/* add the freed block to the block at p */
p->size += bp->size;
p->next = bp->next;
} else
p->next = bp;
freep = p;
p bp ap p->next
5
8 3 7 5
Free(): Above and Below Free
/* Look to see if we're adjacent to the block after the freed block */
if ((char *)bp + bp->size * Headersize == p->next) {
bp->size += p->next->size;
bp->next = p->next->next;
} else
bp->next = p->next;
/* Look to see if we're adjacent to the block before the freed block */
if ((char *)p + p->size * Headersize == bp) {
/* add the freed block to the block at p */
p->size += bp->size;
p->next = bp->next;
} else
p->next = bp;
freep = p;
p
bp ap p->next
15 10
5 3 7 5
Section of morecore() Code 2
/* Don't ask for any less than NALLOC */
if (nu < NALLOC)
nu = NALLOC;
cp = sbrk(nu * Headersize);
if (cp == (char *) -1) /* no space */ Stack
return NULL;
Today's number is
16,661
Memory Management
What are the equivalents of malloc and free in Java? Python?