Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
82 views97 pages

Malloc

The document discusses different approaches for memory management in C programs, including using sbrk and mmap instead of malloc. It notes that while sbrk can be more economical in terms of memory usage, it is slower than malloc due to needing to interact with the kernel for each allocation. Mmap is wasteful as it allocates memory in large pages even if a smaller amount is requested. The standard C allocation functions like malloc are generally preferred as they balance utilization, throughput, and complexity.

Uploaded by

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

Malloc

The document discusses different approaches for memory management in C programs, including using sbrk and mmap instead of malloc. It notes that while sbrk can be more economical in terms of memory usage, it is slower than malloc due to needing to interact with the kernel for each allocation. Mmap is wasteful as it allocates memory in large pages even if a smaller amount is requested. The standard C allocation functions like malloc are generally preferred as they balance utilization, throughput, and complexity.

Uploaded by

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

Memory Management with mmap

What if we use mmap instead of malloc always?

✘ Wasteful low utilization


need 16 bytes, get 4096

✘ Slow low throughput


have to interact with kernel every time,
and those 4096 bytes are all zeroed

✘ Complicated
have to remember the size to unmap

���
Process Memory Layout

... inaccessible to
kernel virtual memory user code
stack
(created at runtime)
%rsp

shared libraries
(code and data)

brk
heap

}
read+write data
(.data, .bss) loaded from
read-only data executable
(.text, .rodata)
0x400000
unused

5
Memory Management with sbrk
#include <unistd.h>

void *sbrk(intptr_t increment);

Grows the program break, a.k.a. brk, and returns


the old program break
Effectively, allocates increment bytes

Do not use sbrk in a program that also uses malloc


or anything that calls malloc (such as printf)

���
Memory Management with sbrk

What if we use sbrk instead of malloc always?

✓ Economical good utilization, at frst


need 16 bytes, get 16

✘ Somewhat slow somewhat low throughput


have to interact with kernel every time

✘ Complicated
have to remember the size to unsbrk(?)

✘ Inexpressive low utilization when done with data


at best, can free last chunk allocated

����
Standard C Allocation
#include <stdlib.h>

void *malloc(size_t size);


void free(void *p);

void *calloc(size_t count, size_t size);


void *realloc(void *p, size_t new_size);

malloc allocates at least size bytes


free accepts a pointer (just once) from malloc
behind the scenes: mmap or sbrk, maybe munmap

calloc is multiply, then malloc, then bzero


realloc is malloc, then memcpy, then free
maybe with a shortcut ��
Allocation Example

p1 = malloc(4)

p2 = malloc(5)

p3 = malloc(6)

free(p2)

p4 = malloc(2)

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


�����
Allocation: Application Side

Rights:
• Call freely interleave malloc and free

Responsibilities:
• Must write to only allocated (not-yet-freed) blocks
• Must call free only once on each malloc result
• Must call free enough to limit memory use

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


�5���
Allocation: Allocator Side

Rights:
• Can pick arbitrary virtual addresses
within alignment constraints

Responsibilities:
• Must accept any size request
• Must accept any number of requests
• Must return non-overlapping blocks
• Must not write to allocated (not-yet-freed) blocks
• Must respond immediately (i.e., can’t reorder requests)

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


�����
Allocation: Performance Goals

Utilization — use as few pages as possible


aggregate payload
measure as
pages used

• malloc(n) ⇒ payload size n


• Sum of n not yet freed = aggregate payload

Throughput — malloc/free as fast as possible


number of operations performed
measure as
seconds used

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


�����
Allocator Design Questions

p1 = malloc(4)

p2 = malloc(5)

p3 = malloc(6)

free(p2)

p4 = malloc(2)

��
Allocator Design Questions

p1 = malloc(4)

p2 = malloc(5)
1 How does free know an
allocated block’s size?
p3 = malloc(6)

free(p2)

p4 = malloc(2)

��
Allocator Design Questions

p1 = malloc(4)

p2 = malloc(5)
2 How is unallocated space
p3 = malloc(6) represented?

free(p2)

p4 = malloc(2)

��
Allocator Design Questions

p1 = malloc(4)

p2 = malloc(5)

p3 = malloc(6)

free(p2)

p4 = malloc(2)

3 How is unallocated space selected


for each allocation?

��
Allocator Design Questions

p1 = malloc(4)

p2 = malloc(5)

p3 = malloc(6)

free(p2)

p4 = malloc(2)

4 How fnely is unallocated space


tracked?

�5
Allocator Design Questions

p1 = malloc(4)

p2 = malloc(5)

p3 = malloc(6)

free(p2)

p4 = malloc(2)

5 When are more pages needed


from the kernel?

��
Allocator Design Questions

1 How does free know an allocated block’s size?

2 How is unallocated space represented?

3 How is unallocated space selected for each allocation?

4 How fnely is unallocated space tracked?

5 When are more pages needed from the kernel?

��
Naive sbrk Allocator

p1 = malloc(4)

p2 = malloc(5)

p3 = malloc(6)

free(p2)

p4 = malloc(2)

��
Naive sbrk Allocator

p1 = malloc(4)
1 How does free know an
p2 = malloc(5)
allocated block’s size?
It doesn’t
p3 = malloc(6)

free(p2)

p4 = malloc(2)

��
Naive sbrk Allocator

p1 = malloc(4)
2 How is unallocated space
p2 = malloc(5) represented?

p3 = malloc(6) It isn’t

free(p2)

p4 = malloc(2)

��
Naive sbrk Allocator

3 How is unallocated space selected


p1 = malloc(4) for each allocation?

p2 = malloc(5) Always add to the end

p3 = malloc(6)

free(p2)

p4 = malloc(2)

��
Naive sbrk Allocator

p1 = malloc(4)

p2 = malloc(5)
4 How fnely is unallocated space
p3 = malloc(6) tracked?

free(p2) Nothing to track

p4 = malloc(2)

��
Naive sbrk Allocator

p1 = malloc(4)

p2 = malloc(5)

p3 = malloc(6)

free(p2)

p4 = malloc(2)

5 When are more pages needed


from the kernel?
Every allocation
��
Naive sbrk Allocator

Real allocator needs to produce pointers aligned on 16 bytes:


#define ALIGNMENT 16
#define ALIGN(size) (((size) + (ALIGNMENT-1)) & ~(ALIGNMENT-1))
Copy

void *mm_malloc(size_t size) {


return sbrk(ALIGN(size));
}

void mm_free(void *p) {


}
Copy

4 How fnely is unallocated space tracked?


Some unallocated space can be left in a block for alignment
padding
�����
Picture Conventions

Since an implementation aligns to 16 bytes:

= 16 bytes, a “word”

N = N×16 bytes

p1 = malloc(4)

allocation of 64 bytes

�����
Naive Chunked sbrk Allocator

Chunk size of 6:

p1 = malloc(4)

p2 = malloc(5)

p3 = malloc(6)

free(p2)

p4 = malloc(2)

��
Naive Chunked sbrk Allocator

Chunk size of 6:

p1 = malloc(4)

p2 = malloc(5)

p3 = malloc(6)

free(p2) 5 When are more pages needed


from the kernel?
p4 = malloc(2)
When more is needed for an allocation

5�
Naive Chunked sbrk Allocator

Pick a chunk size:

#define CHUNK_SIZE (1 << 14)


#define CHUNK_ALIGN(size) (((size)+(CHUNK_SIZE-1)) & ~(CHUNK_SIZE-1))
Copy

5�
Naive Chunked sbrk Allocator

void *current_avail = NULL;


size_t current_avail_size = 0;

int mm_init() {
current_avail = sbrk(0);
current_avail_size = 0;
return 0;
}
Copy

5�
Naive Chunked sbrk Allocator

void *mm_malloc(size_t size) {


size_t newsize = ALIGN(size);
void *p;

if (current_avail_size < newsize) {


sbrk(CHUNK_ALIGN(newsize));
current_avail_size += CHUNK_ALIGN(newsize);
}

p = current_avail;
current_avail += newsize;
current_avail_size -= newsize;

return p;
}
Copy

5�
Naive mmap Allocator

Page size of 8:

p1 = malloc(4)
p2 = malloc(5)
p3 = malloc(6)
free(p2)
p4 = malloc(2)

5�
Naive mmap Allocator
5 When are more pages needed
from the kernel?

Page size of 8: When the most recent page doesn’t


have space
p1 = malloc(4)
p2 = malloc(5)
p3 = malloc(6)
free(p2)
p4 = malloc(2)

55
Naive mmap Allocator

void *current_avail = NULL;


size_t current_avail_size = 0;

void *mm_malloc(size_t size) {


size_t newsize = ALIGN(size);
void *p;

if (current_avail_size < newsize) {


current_avail = mmap(0, CHUNK_ALIGN(newsize),
PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON,
-1, 0);
current_avail_size = CHUNK_ALIGN(newsize);
}

p = current_avail;
current_avail += newsize;
current_avail_size -= newsize;

return p;
}
Copy

5�
Fragmentation

Unallocated space in mapped pages is wasted

Naive sbrk:

Naive mmap:

5�
Fragmentation

Unallocated space in mapped pages is wasted

Naive sbrk:

Naive mmap:

wasted space = fragmentation

5�
Fragmentation

Unallocated space in mapped pages is wasted

Naive sbrk:

Naive mmap:

Pick page chunk ≫ allocation size

5�
Fragmentation

Unallocated space in mapped pages is wasted

Naive sbrk:

Naive mmap:

��
Fragmentation

Unallocated space in mapped pages is wasted

Naive sbrk:

Naive mmap:

Taking free into account, both naive implementations


suffer from extreme fragmentation
... so we need to keep track of unallocated space

��
Allocation Bit in a Block Header

p1 = malloc(4) 1 0

p2 = malloc(5) 1 1 0

p3 = malloc(6) 1 1 1 0

free(p2) 1 0 1 0

p4 = malloc(2) 1 1 0 1 0

��
Allocation Bit in a Block Header

p1 = malloc(4) 1 0

p2 = malloc(5) 1 1 0

p3 = malloc(6) 1 1 1 0

free(p2) 1 0 1 0

p4 = malloc(2) 1 1 0 1 0

��
Size + Allocation Bit in a Block Header

20
0

p1 = malloc(4) 5 15
0
1

p2 = malloc(5) 5 6 9
1 1 0

p3 = malloc(6) 5 6 7 2
1 1 1 0

free(p2) 5 6 7 2
1 0 1 0

p4 = malloc(2) 5 3 3 7 2
1 1 0 1 0

��
Sizes in a Block Header ⇒ Implicit Free List

20
0

p1 = malloc(4) 5 15
0
1

p2 = malloc(5) 5 6 9
1 1 0

p3 = malloc(6) 5 6 7 2
1 1 1 0

free(p2) 5 6 7 2
1 0 1 0

p4 = malloc(2) 5 3 3 7 2
1 1 0 1 0

�5
Sizes in a Block Header ⇒ Implicit Free List

20
0

p1 = malloc(4) 5 15
0
1

p2 = malloc(5) 5 6 9
1 1 0

p3 = malloc(6) 5 6 7 2
1 1 1 0

free(p2) 5 6 1 How does 7 free know an2


1 0 1 0
allocated block’s size?

p4 = malloc(2) 5 3 It’s stored


3 at7the start of the block
2
1 1 0 1 0

��
Sizes in a Block Header ⇒ Implicit Free List

20
0

p1 = malloc(4) 5 15
0
1

p2 = malloc(5) 5 6 9
1 1 0

p3 = malloc(6) 5 6 7 2
1 1 1 0

free(p2) 5 6 7 2
1 0 1 0

2 How is unallocated
p4 = malloc(2) 5 space
3 represented?
3 7 2
1 1 0 1 0

A bit in the block header distinguishes allocated from


unallocated
��
Sizes in a Block Header ⇒ Implicit Free List

20
0

p1 = malloc(4) 5 15
0
1

3 How is unallocated space selected


p2 = malloc(5) 5for each allocation?
6 9
1 1 0

Search the chain for a block that’s free


p3 = malloc(6) and
5 big enough6 7 2
1 1 1 0

free(p2) 5 6 7 2
1 0 1 0

p4 = malloc(2) 5 3 3 7 2
1 1 0 1 0

��
Sizes in a Block Header ⇒ Implicit Free List

20
0

p1 = malloc(4) 5 15
0
1

4 How fnely is unallocated space


p2 = malloc(5) 5 tracked?
6 9
1 1 0

A block should be of size 2 or more to


p3 = malloc(6) 5 be useful 6 7 2
1 1 1 0

free(p2) 5 6 7 2
1 0 1 0

p4 = malloc(2) 5 3 3 7 2
1 1 0 1 0

��
Sizes in a Block Header ⇒ Implicit Free List

20
0

p1 = malloc(4) 5 15
0
1

5 When are more pages needed


p2 = malloc(5) 5 6 9
1 1
from the kernel?
0

p3 = malloc(6) 5 When a search 7through the chain2


6
1
doesn’t fnd a free block that’s big
1 1 0

enough
free(p2) 5 6 7 2
1 0 1 0

p4 = malloc(2) 5 3 3 7 2
1 1 0 1 0

��
Terminating the Block List

5 3 3 7 2
1 1 0 1 0

How does the allocator know that the size-2 block is the last one?

Compare the next pointer to an end-of-heap address


end

5 3 3 7 2
1 1 0 1 0

or Add a “zero”-sized block to terminate the chain

5 3 3 7 2 0
1 1 0 1 0 1

�����
Storing the Size and Allocation Bit
p2

6 9
1 0

typedef struct {
size_t size;
char allocated;
} block_header;
Copy

��
Storing the Size and Allocation Bit
p2

6 9
1 0

typedef struct {
size_t size;
char allocated;
} block_header;
Copy

��
Storing the Size and Allocation Bit
block payload
bp

block_header block_header

typedef struct {
size_t size;
char allocated;
} block_header;
Copy

�5
Storing the Size and Allocation Bit
bp

block_header block_header

typedef struct {
size_t size;
char allocated;
} block_header;
Copy

sizeof(block_header) = 16

Aligned payload size ⇒ 16-byte alignment preserved


... although that’s a lot of empty space

��
Storing the Size and Allocation Bit
bp

block_header block_header

typedef struct {
size_t size;
char allocated;
} block_header;
Copy

Macro for block overhead:


#define OVERHEAD sizeof(block_header)
Copy

��
Storing the Size and Allocation Bit
HDRP(bp) bp

block_header block_header

typedef struct {
size_t size;
char allocated;
} block_header;
Copy

Macro for getting the header from a payload pointer:


#define HDRP(bp) ((char *)(bp) - sizeof(block_header))
Copy

��
Storing the Size and Allocation Bit
p bp

block_header block_header

typedef struct {
size_t size;
char allocated;
} block_header;
Copy

Macros for working with a raw pointer as the header:


#define GET_SIZE(p) ((block_header *)(p))->size
#define GET_ALLOC(p) ((block_header *)(p))->allocated
Copy

��
Storing the Size and Allocation Bit
bp NEXT_BLKP(bp)

block_header block_header

typedef struct {
size_t size;
char allocated;
} block_header;
Copy

Macro for getting the next block’s payload:


#define NEXT_BLKP(bp) ((char *)(bp) + GET_SIZE(HDRP(bp)))
Copy

��
Initializing the Allocator

brk

void *first_bp;

int mm_init() {
sbrk(sizeof(block_header));
first_bp = sbrk(0);

GET_SIZE(HDRP(first_bp)) = 0;
GET_ALLOC(HDRP(first_bp)) = 1;

return 0;
}
Copy

��
Initializing the Allocator

brk

void *first_bp;

int mm_init() {
sbrk(sizeof(block_header));
first_bp = sbrk(0);

GET_SIZE(HDRP(first_bp)) = 0;
GET_ALLOC(HDRP(first_bp)) = 1;

return 0;
}
Copy

��
Initializing the Allocator

first_bp
brk

void *first_bp;

int mm_init() {
sbrk(sizeof(block_header));
first_bp = sbrk(0);

GET_SIZE(HDRP(first_bp)) = 0;
GET_ALLOC(HDRP(first_bp)) = 1;

return 0;
}
Copy

��
Initializing the Allocator

first_bp
brk

0
1

void *first_bp;

int mm_init() {
sbrk(sizeof(block_header));
first_bp = sbrk(0);

GET_SIZE(HDRP(first_bp)) = 0;
GET_ALLOC(HDRP(first_bp)) = 1;

return 0;
}
Copy

��
Adding Pages

first_bp
brk

0
1

void extend(size_t new_size) {


size_t chunk_size = CHUNK_ALIGN(new_size);
void *bp = sbrk(chunk_size);

GET_SIZE(HDRP(bp)) = chunk_size;
GET_ALLOC(HDRP(bp)) = 0;

GET_SIZE(HDRP(NEXT_BLKP(bp))) = 0;
GET_ALLOC(HDRP(NEXT_BLKP(bp))) = 1;
}
Copy

�5
Adding Pages

first_bp
brk

0
1

void extend(size_t new_size) {


size_t chunk_size = CHUNK_ALIGN(new_size);
void *bp = sbrk(chunk_size);

GET_SIZE(HDRP(bp)) = chunk_size;
GET_ALLOC(HDRP(bp)) = 0;

GET_SIZE(HDRP(NEXT_BLKP(bp))) = 0;
GET_ALLOC(HDRP(NEXT_BLKP(bp))) = 1;
}
Copy

��
Adding Pages

first_bp
bp brk

0
1

void extend(size_t new_size) {


size_t chunk_size = CHUNK_ALIGN(new_size);
void *bp = sbrk(chunk_size);

GET_SIZE(HDRP(bp)) = chunk_size;
GET_ALLOC(HDRP(bp)) = 0;

GET_SIZE(HDRP(NEXT_BLKP(bp))) = 0;
GET_ALLOC(HDRP(NEXT_BLKP(bp))) = 1;
}
Copy

��
Adding Pages

first_bp
bp brk

6
0

void extend(size_t new_size) {


size_t chunk_size = CHUNK_ALIGN(new_size);
void *bp = sbrk(chunk_size);

GET_SIZE(HDRP(bp)) = chunk_size;
GET_ALLOC(HDRP(bp)) = 0;

GET_SIZE(HDRP(NEXT_BLKP(bp))) = 0;
GET_ALLOC(HDRP(NEXT_BLKP(bp))) = 1;
}
Copy

��
Adding Pages

first_bp
bp brk

6 0
0 1

void extend(size_t new_size) {


size_t chunk_size = CHUNK_ALIGN(new_size);
void *bp = sbrk(chunk_size);

GET_SIZE(HDRP(bp)) = chunk_size;
GET_ALLOC(HDRP(bp)) = 0;

GET_SIZE(HDRP(NEXT_BLKP(bp))) = 0;
GET_ALLOC(HDRP(NEXT_BLKP(bp))) = 1;
}
Copy

��
Adding Pages

first_bp
brk

3 5 3 0
1 1 0 1

void extend(size_t new_size) {


size_t chunk_size = CHUNK_ALIGN(new_size);
void *bp = sbrk(chunk_size);

GET_SIZE(HDRP(bp)) = chunk_size;
GET_ALLOC(HDRP(bp)) = 0;

GET_SIZE(HDRP(NEXT_BLKP(bp))) = 0;
GET_ALLOC(HDRP(NEXT_BLKP(bp))) = 1;
}
Copy

��
Adding Pages

first_bp
bp brk

3 5 3 0
1 1 0 1

void extend(size_t new_size) {


size_t chunk_size = CHUNK_ALIGN(new_size);
void *bp = sbrk(chunk_size);

GET_SIZE(HDRP(bp)) = chunk_size;
GET_ALLOC(HDRP(bp)) = 0;

GET_SIZE(HDRP(NEXT_BLKP(bp))) = 0;
GET_ALLOC(HDRP(NEXT_BLKP(bp))) = 1;
}
Copy

��
Adding Pages

first_bp
bp brk

3 5 3 6
1 1 0 0

void extend(size_t new_size) {


size_t chunk_size = CHUNK_ALIGN(new_size);
void *bp = sbrk(chunk_size);

GET_SIZE(HDRP(bp)) = chunk_size;
GET_ALLOC(HDRP(bp)) = 0;

GET_SIZE(HDRP(NEXT_BLKP(bp))) = 0;
GET_ALLOC(HDRP(NEXT_BLKP(bp))) = 1;
}
Copy

��
Adding Pages

first_bp
bp brk

3 5 3 6 0
1 1 0 0 1

void extend(size_t new_size) {


size_t chunk_size = CHUNK_ALIGN(new_size);
void *bp = sbrk(chunk_size);

GET_SIZE(HDRP(bp)) = chunk_size;
GET_ALLOC(HDRP(bp)) = 0;

GET_SIZE(HDRP(NEXT_BLKP(bp))) = 0;
GET_ALLOC(HDRP(NEXT_BLKP(bp))) = 1;
}
Copy

��
Finding a Block to Allocate
first_bp

4 5 6 0
1 0 1 1

void *mm_malloc(size_t size) {


int new_size = ALIGN(size + OVERHEAD);
void *bp = first_bp;

while (GET_SIZE(HDRP(bp)) != 0) {
if (!GET_ALLOC(HDRP(bp))
&& (GET_SIZE(HDRP(bp)) >= new_size)) {
set_allocated(bp, new_size);
return bp;
}
bp = NEXT_BLKP(bp);
}

extend(new_size);
set_allocated(bp, new_size);
return bp;
}
Copy
��
Finding a Block to Allocate
first_bp bp (if no room found)

4 5 6 0
1 0 1 1

void *mm_malloc(size_t size) {


int new_size = ALIGN(size + OVERHEAD);
void *bp = first_bp;

while (GET_SIZE(HDRP(bp)) != 0) {
if (!GET_ALLOC(HDRP(bp))
&& (GET_SIZE(HDRP(bp)) >= new_size)) {
set_allocated(bp, new_size);
return bp;
}
bp = NEXT_BLKP(bp);
}

extend(new_size);
set_allocated(bp, new_size);
return bp;
}
Copy
�5
Marking a Block as Allocated

bp

4 5 6 0
1 0 1 1

void set_allocated(void *bp, size_t size) {


size_t extra_size = GET_SIZE(HDRP(bp)) - size;

if (extra_size > ALIGN(1 + OVERHEAD)) {


GET_SIZE(HDRP(bp)) = size;
GET_SIZE(HDRP(NEXT_BLKP(bp))) = extra_size;
GET_ALLOC(HDRP(NEXT_BLKP(bp))) = 0;
}

GET_ALLOC(HDRP(bp)) = 1;
}
Copy

��
Marking a Block as Allocated

bp if size > 3

4 5 6 0
1 1 1 1

void set_allocated(void *bp, size_t size) {


size_t extra_size = GET_SIZE(HDRP(bp)) - size;

if (extra_size > ALIGN(1 + OVERHEAD)) {


GET_SIZE(HDRP(bp)) = size;
GET_SIZE(HDRP(NEXT_BLKP(bp))) = extra_size;
GET_ALLOC(HDRP(NEXT_BLKP(bp))) = 0;
}

GET_ALLOC(HDRP(bp)) = 1;
}
Copy

��
Marking a Block as Allocated

bp

4 5 6 0
1 0 1 1

void set_allocated(void *bp, size_t size) {


size_t extra_size = GET_SIZE(HDRP(bp)) - size;

if (extra_size > ALIGN(1 + OVERHEAD)) {


GET_SIZE(HDRP(bp)) = size;
GET_SIZE(HDRP(NEXT_BLKP(bp))) = extra_size;
GET_ALLOC(HDRP(NEXT_BLKP(bp))) = 0;
}

GET_ALLOC(HDRP(bp)) = 1;
}
Copy

��
Marking a Block as Allocated

bp if size ≤ 3: split

4 3 6 0
1 0 1 1

void set_allocated(void *bp, size_t size) {


size_t extra_size = GET_SIZE(HDRP(bp)) - size;

if (extra_size > ALIGN(1 + OVERHEAD)) {


GET_SIZE(HDRP(bp)) = size;
GET_SIZE(HDRP(NEXT_BLKP(bp))) = extra_size;
GET_ALLOC(HDRP(NEXT_BLKP(bp))) = 0;
}

GET_ALLOC(HDRP(bp)) = 1;
}
Copy

��
Marking a Block as Allocated

bp if size ≤ 3: split

4 3 2 6 0
1 0 0 1 1

void set_allocated(void *bp, size_t size) {


size_t extra_size = GET_SIZE(HDRP(bp)) - size;

if (extra_size > ALIGN(1 + OVERHEAD)) {


GET_SIZE(HDRP(bp)) = size;
GET_SIZE(HDRP(NEXT_BLKP(bp))) = extra_size;
GET_ALLOC(HDRP(NEXT_BLKP(bp))) = 0;
}

GET_ALLOC(HDRP(bp)) = 1;
}
Copy

���
Marking a Block as Allocated

bp if size ≤ 3: split

4 3 2 6 0
1 1 0 1 1

void set_allocated(void *bp, size_t size) {


size_t extra_size = GET_SIZE(HDRP(bp)) - size;

if (extra_size > ALIGN(1 + OVERHEAD)) {


GET_SIZE(HDRP(bp)) = size;
GET_SIZE(HDRP(NEXT_BLKP(bp))) = extra_size;
GET_ALLOC(HDRP(NEXT_BLKP(bp))) = 0;
}

GET_ALLOC(HDRP(bp)) = 1;
}
Copy

���
Freeing a Block

bp

4 5 6 0
1 1 1 1

void mm_free(void *bp) {


GET_ALLOC(HDRP(bp)) = 0;
}
Copy

���
Freeing a Block

bp

4 5 6 0
1 0 1 1

void mm_free(void *bp) {


GET_ALLOC(HDRP(bp)) = 0;
}
Copy

���
Freeing Multiple Blocks

2 3 3 4 0
1 1 1 1 1

free(p2) 2 3 3 4 0
1 0 1 1 1

free(p3) 2 3 3 4 0
1 0 0 1 1

malloc(5)

���
Freeing Multiple Blocks

2 3 3 4 0
1 1 1 1 1

free(p2) 2 3 3 4 0
1 0 1 1 1

free(p3) 2 3 3 4 0
1 0 0 1 1

there’s room here, but no


malloc(5) unallocated block is big enough ⇒
extra fragmentation

��5
Freeing Multiple Blocks

2 3 3 4 0
1 1 1 1 1

free(p2) 2 3 3 4 0
1 0 1 1 1

free(p3) 2 3 3 4 0
1 0 0 1 1

malloc(5)

free should coalesce adjacent unallocated blocks

���
Coalescing Unallocated Blocks

Needed invariant: no two unallocated blocks are adjacent


can maintain at each free call
For free(p2):

3 4 3 no merge 3 4 3
1 1 1 1 0 1

3 4 3 merge with 3 7
1 1 0
next block 1 0

3 4 3 merge with 7 3
0 1 1
previous block 0 1

3 4 3 merge with 10
both blocks
0 1 0 0

�������
Coalescing Unallocated Blocks

Needed invariant: no two unallocated blocks are adjacent


can maintain at each free call
For free(p2):

3 4 3 no merge 3 4 3
1 1 1 1 0 1

3 4 3 merge with 3 7
1 1 0
next block 1 0

Need to fnd the block before p2

3 4 3 merge with 7 3
0 1 1
previous block 0 1

3 4 3 merge with 10
both blocks
0 1 0 0

���
Blocks with Headers and Footers

4 45 54 4
1 1 1

���
Blocks with Headers and Footers

4 45 54 4
1 1 1

typedef struct {
size_t size;
int filler;
} block_footer;
Copy

���
Blocks with Headers and Footers

4 45 54 4
1 1 1

typedef struct {
Same place as in
size_t size; block_header
int filler;
} block_footer;
Copy

���
Blocks with Headers and Footers

4 45 54 4
1 1 1

typedef struct {
size_t size;
int filler;
} block_footer;
Copy

#define OVERHEAD (sizeof(block_header)+sizeof(block_footer))


Copy

���
Blocks with Headers and Footers

PREV_BLKP(bp) bp

4 45 54 4
1 1 1

typedef struct {
size_t size;
int filler;
} block_footer;
Copy

#define PREV_BLKP(bp) ((char *)(bp)-GET_SIZE((char *)(bp)-OVERHEAD))


Copy

���
Blocks with Headers and Footers

PREV_BLKP(bp) bp FTRP(bp)

4 45 54 4
1 1 1

typedef struct {
size_t size;
int filler;
} block_footer;
Copy

#define FTRP(bp) ((char *)(bp)+GET_SIZE(HDRP(bp))-OVERHEAD)


Copy

��5
Setting Block Sizes in Footers

void extend(size_t new_size) {


....
GET_SIZE(HDRP(bp)) = chunk_size;
GET_SIZE(FTRP(bp)) = chunk_size;
....
}

void set_allocated(void *bp, size_t size) {


....
GET_SIZE(HDRP(bp)) = size;
GET_SIZE(FTRP(bp)) = size;
GET_SIZE(HDRP(NEXT_BLKP(bp))) = extra_size;
GET_SIZE(FTRP(NEXT_BLKP(bp))) = extra_size;
....
}
Copy

���
Coalescing after Free

void mm_free(void *bp) {


GET_ALLOC(HDRP(bp)) = 0;
coalesce(bp);
}
Copy

���
Coalescing Free Blocks
void *coalesce(void *bp) {
size_t prev_alloc = GET_ALLOC(HDRP(PREV_BLKP(bp)));
size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp)));
size_t size = GET_SIZE(HDRP(bp));
....

return bp;
}
Copy

���
Coalescing Free Blocks
void *coalesce(void *bp) {
size_t prev_alloc = GET_ALLOC(HDRP(PREV_BLKP(bp)));
size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp)));
size_t size = GET_SIZE(HDRP(bp));

if (prev_alloc && next_alloc) { /* Case 1 */


/* nothing to do */
}
....
}
Copy

bp bp
no merge
4 4 50 5 41 4 4 4 50 5 41 4
1 1

���
Coalescing Free Blocks
void *coalesce(void *bp) {
size_t prev_alloc = GET_ALLOC(HDRP(PREV_BLKP(bp)));
size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp)));
size_t size = GET_SIZE(HDRP(bp));
....

else if (prev_alloc && !next_alloc) { /* Case 2 */


size += GET_SIZE(HDRP(NEXT_BLKP(bp)));
GET_SIZE(HDRP(bp)) = size;
GET_SIZE(FTRP(bp)) = size;
}
....
}
Copy

bp bp
merge with
4 next block
1
4 50 5 40 4 4
1
4 90 9

���
Coalescing Free Blocks
void *coalesce(void *bp) {
size_t prev_alloc = GET_ALLOC(HDRP(PREV_BLKP(bp)));
size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp)));
size_t size = GET_SIZE(HDRP(bp));
....

else if (!prev_alloc && next_alloc) { /* Case 3 */


size += GET_SIZE(HDRP(PREV_BLKP(bp)));
GET_SIZE(FTRP(bp)) = size;
GET_SIZE(HDRP(PREV_BLKP(bp))) = size;
bp = PREV_BLKP(bp);
}
....
}
Copy

bp bp
merge with
4 previous block
0
4 50 5 41 4 9
0
9 41 4

���
Coalescing Free Blocks
void *coalesce(void *bp) {
size_t prev_alloc = GET_ALLOC(HDRP(PREV_BLKP(bp)));
size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp)));
size_t size = GET_SIZE(HDRP(bp));
....

else { /* Case 4 */
size += (GET_SIZE(HDRP(PREV_BLKP(bp)))
+ GET_SIZE(HDRP(NEXT_BLKP(bp))));
GET_SIZE(HDRP(PREV_BLKP(bp))) = size;
GET_SIZE(FTRP(NEXT_BLKP(bp))) = size;
bp = PREV_BLKP(bp);
}
....
}
Copy

bp bp
merge with
4 both blocks
0
4 50 5 40 4 13
0
13

���
Prolog Block

Create a prolog block so coalesce can always look backwards

2 2 22
0
22 0
1 1

int mm_init() {
....
mm_malloc(0); /* never freed */
....
}
Copy

���

You might also like