You are on page 1of 30

System Software

Prof. Dr. H. Mssenbck

1. Memory Management
2. Garbage Collection
3. Linkers and Loaders
4. Debuggers
5. Text Editors
Marks obtained by end-term exam
http://ssw.jku.at/Misc/SSW/

1. Memory Management
1.1
1.2
1.3
1.4
1.5
1.6

Overview
Allocation and deallocation of memory
Single free list
Multiple free lists
Buddy system
Memory fragmentation

Main tasks of memory management


Allocation and deallocation of memory
global data

global variables, code

managed by the loader

stack

local variables

managed by the compiler

heap

dynamically created objects

managed by the run-time system

Reclaiming unused memory (garbage collection)


p

p = q;

Dealing with memory fragmentation

Paging and swapping (virtual memory)


not discussed in this course
3

1. Memory Management
1.1
1.2
1.3
1.4
1.5
1.6

Overview
Allocation and deallocation of memory
Single free list
Multiple free lists
Buddy system
Memory fragmentation

Stack-like management of the heap


mark/alloc/free
top

top

top

a
top

m = mark();

a = alloc(size);

returns the current


end of the heap (top)

allocates a block
of size size and
returns its address a

more alloc() calls

free(m);

resets the heap end to m


(deallocates anything that
was allocated after mark())

Advantage

Disadvantage

simple and efficient

objects must be deallocated in LIFO order


(applicable e.g. for the symbol table of
a compiler)

int alloc(int size) {


if (top + size > heapEnd) {
error(...); a = 0;
} else {
a = top; top = top + size;
}
return a;
}

void free(int m) {
top = m;
}

Heap management with a free list


allocation of a block

a = alloc(size);

deallocation of a block

dealloc(a);

May lead to holes in the heap, which


must be maintained by a free list

heap
free

(free list)

alloc() must allocate a block from the free list, i.e.:


find a sufficiently large block in the free list
remove it from the free list
dealloc()
add the deallocated block to the free list
merge the block with free neighbors

1. Memory Management
1.1
1.2
1.3
1.4
1.5
1.6

Overview
Allocation and deallocation of memory
Single free list
Multiple free lists
Buddy system
Memory fragmentation

Single free list


All blocks are linked into a single large list

heap
free

Possible sort orders of the free list


1. LIFO: the most recently deallocated block is the first in the list.
Simple to implement
2. FIFO: the most recently deallocated block is the last in the list.
3. Blocks are sorted by address.
Simple block merging; slow insert
4. Blocks are sorted by their size.
Simple search of a suitable block; slow insert

Possible block format


p

used block

length

free block

length

data

next

unused

This format implies a minimum block size (e.g. 8 bytes)

Why do we need the length of used blocks?


It allows us to traverse the heap sequentially: p = p + p.length;

Allocation of blocks
p = alloc(size);

Strategies for searching the free list


First Fit

returns the first suitable block with length >= size + 4


+ simple and efficient
- causes fragmentation (small blocks accumulate at the beginning of the list)

Best Fit

returns the block with the smallest waste (blocks are split)
blockj: lengthj >= (size+4) && i j: lengthi >= lengthj
+ minimum waste
- slow (must traverse the whole list; good if the list is sorted by block size)

Next Fit

variant of First Fit


free blocks are linked cyclically;
the search starts where it ended last time
free
free

10

Splitting free blocks


Free block
free list
0

len next

unused

len

Splitting
p = alloc(size);

unused

len' next

used

len''
p

len'

size
len''

The block is cut off from the end => next does not have to be changed
If less than 8 bytes would remain the whole block is used
11

Allocation of blocks (pseudo code)


static Block free; // free list
static Block alloc (int size) {
Block start = free;
Block prev = free; free = free.next;
while (free.len < size+4 && free != start) {
prev = free; free = free.next;
}
if (free == start) { error(...); return null; }
else {
Block p = free;
int newLen = p.len - (size+4);
if (newLen >= 8) { // split block
p = (Block)(p - 4 + p.len - size);
p.len = size + 4;
free.len = newLen;
} else if (free == prev) { // last free block
free = null;
} else { // remove block from list
prev.next = free.next; free = prev;
}
Set all data bytes in block p to 0;
p.used = true;
return p;
}
}

free

prev

free

len
0 len

next
size

p
free

newLen
0 nL

next

free

len
1 len

size

12

Deallocation of blocks
dealloc(p);

free

left

right

- merge blockp with free neighbors


- add merged block to the free list
void dealloc (Block p) {
left = left neighbor of p;
if (!left.used) {
merge left and p; p = left;
} else {
add p to free list;
}
right = right neighbor of p;
if (!right.used) {
remove right from free list;
merge p and right;
}
}

// traverse heap sequentially


// enlarge left.len; left remains in free list

// right = (Block)(p + p.len);


// seq. search of right's predecessor
// p is already in the free list

Requires sequential traversals of the heap and the free list => slow
13

Boundary tags
In order to avoid the sequential searching of blocks

Free list is doubly linked

length and used bit are also stored at the block end (also in used blocks)
0 len next prev

0 len

minimum block size = 16 bytes

right neighbor of p:
left neighbor of p:
successor of p in free list:
predecessor of p in free list:

p + p.len
p - (p-8).len
p.next
p.prev

There must be a used dummy block at the beginning and the end of the heap.
14

Lazy merge
dealloc(p) does not merge free blocks with their neighbors

free

p
p.next = free;
free = p;
free

If alloc() does not find a sufficiently large block:


traverse the heap sequentially
merge adjacent free blocks
build new free list
p = heapStart; free = null;
while (p < heapEnd) {
if (!p.used) {
while (right neighbor of p is free) merge neighbor with p;
add p to free list;
}
p = (Block)(p + p.len);
}

free

15

1. Memory Management
1.1
1.2
1.3
1.4
1.5
1.6

Overview
Allocation and deallocation of memory
Single free list
Multiple free lists
Buddy system
Memory fragmentation

16

Allocation of blocks
Observation
90% of all blocks have only one of 5 different sizes

Multiple free lists for blocks of size 2i bytes


free
8
16
32
64
128
256
512
n*1024

...
...

Blocks in the last list have different sizes, but their size is a multiple of 1024 bytes

Strategy for allocating a block of size s


n = next power of 2 greater or equal than s
remove the first block from the list corresponding to n
Any surplus stays with the allocated block (block size is always 2i)

17

Algorithms
Block alloc (int size) {
if (size > 512) {
p = suitable block from the last list (e.g. first fit);
put remaining i*1024 byte back to the last list;
} else {
int s = 8, n = 3;
// free[0..2] are dummies
while (s < size) { s = 2 * s; n++; } // n = log2(size);
if (free[n] == null) split(n+1);
p = free[n]; free[n] = p.next;
// p = first block from free[n]
}
initialize block p with 0;
return p;
}

0
1
2
3
4
5
6
7
8
9
10

8
8
8
16
16
32
64
128
256
512
2048
4096

void split (int n) {


if (n == 10) {
p = cut off 1024 byte block from the last list;
} else {
if (free[n] == null) split(n+1);
p = free[n]; free[n] = p.next;
}
split p into two equally sized blocks and add them to free[n-1];
}
18

Example
Allocation of 40 bytes (given the follwing free lists)
8
16
32
64
128
256
512
n*1024

8 8 8
16 16
32

2048

tries to obtain a block of size 64;


but the 64-list is empty

4096

Split a 1024 byte block and use it to fill the empty lists
8 8 8
16 16
32

2048

4096

8 8 8
16 16
32

8 8 8
16 16
32

8 8 8
16 16
32

512 512
1024 4096

256 256
512
1024 4096

128 128
256
512
1024 4096

8 8 8
16 16
32
64 64
128
256
512
1024 4096

Take a 64 byte block leaving 24 bytes unused (internal fragmentation)


In most cases a suitable block is found with a single access => efficient
At the beginning the whole heap is a single block in the 1024-list

19

Deallocation of blocks
void dealloc (Block p) {
int s = 8, n = 3;
while (s < p.len) { s = 2 * s; n++; } // n = log2(p.len);
if (n > 10) n = 10;
p.next = free[n]; free[n] = p;
// add p to free[n]
}

Blocks are not merged, because a block of the same size is probably needed soon again
(maybe one should do a lazy merge from time to time)

20

Reducing internal fragmentation


... by more block sizes
block sizes
2i

16
8

2i, 3*2i

16
16

k * 16

16

64
32

24
8

32
16

+
-

32

64
32

48
16

128

16

128
48

16

64

256
256
64

16

80
16

512

512
96

32

96
16

1024

128
32

112
16

64

128
16

192

256 ...
64

144
16

160 ...
16

less internal fragmentation


more free lists
more difficult to compute the right list
more complicated to split blocks
21

Reducing internal fragmentation


... by free lists containing blocks of variable sizes (in a certain interval)
list i contains blocks of size 2i .. 2i+1-1

Example
we need a block with 40 bytes
search the list containing blocks of size 32..63;
we find a block of size 58, say
split the block into 40 + 18 bytes
add 18-byte block into list with sizes 16..31
+
+
-

no internal fragmentation
the lists are shorter than with a single free list
the list must be searched for a suitable block (e.g. next fit)
leads to many small blocks of waste
free blocks should be merged lazily from time to time

22

1. Memory Management
1.1
1.2
1.3
1.4
1.5
1.6

Overview
Allocation and deallocation of memory
Single free list
Multiple free lists
Buddy system
Memory fragmentation

23

Idea of the Buddy System


alloc(size)
Multiple free lists with blocks of size 2i
8
16
32
64

8 8
16 16
32 32
64 64

as described above

...

dealloc(p)
Every block has a partner (buddy) of the same size
p
q
p is the buddy of q and vice versa
32 32
A block can only be merged with its buddy
The address of p's buddy can be computed from the address of p

Goal: simple and efficient merging of blocks


24

Buddy addresses
Buddies emerge from splitting blocks of size 2i
Assume that we have a block of size 64 (= 26) at address 0
0
64

If we split this block we obtain two buddies x and y of size 32 (= 25)


0

32
32
x

32
y

adr(x) = 0

=00000000

adr(y) = 32

=00100000

size = 25

If we split y again we obtain


32

48
16
x

16
y

adr(x) = 32

=00100000

adr(y) = 48

=00110000

size = 24

If we split x again we obtain


32 40
8 8
x y

adr(x) = 32

=00100000

adr(y) = 40

=00101000

size = 23

A block of size 2i has an address which is a multiple of 2i (it has i zeroes at the end)
25

Deallocation of a block of size 2i


Merge the block with its buddy if the buddy is free
free

p
heap

void dealloc (Block p) { // size of p = 2i


int s = 8, i = 3, buddy, beg;
while (s < p.len) { s = s * 2; i++; } // s = p.len, i = log2(p.len)
for (;;) {
if ( ((p-4) >> i) % 2 == 1) {
buddy
p
buddy = p - p.len; beg = buddy;
beg
} else {
buddy = p + p.len; beg = p;
p
buddy
}
beg
if (buddy.used || buddy.len != p.len
|| buddy < heapStart || buddy >= heapEnd) break;
remove buddy from free[i]; // seq. search in short list
p = beg; p.len = 2 * p.len;
i++;
}
add p to free[i];
}

p
if p is deallocated,
multiple blocks are
merged

cannot be merged with


its buddy any more
=> add it to the free list

26

1. Memory Management
1.1
1.2
1.3
1.4
1.5
1.6

Overview
Allocation and deallocation of memory
Single free list
Multiple free lists
Buddy system
Memory fragmentation

27

External and internal fragmentation


heap
external fragmentation
small (unusable) holes
between blocks

internal fragmentation
unused bytes within
an allocated block

External fragmentation can be removed by compaction

+ collects all "holes" into a contiguous area of free memory


+ allows simple alloc() without free lists (blocks are cut off from the free area)
- compaction leads to new block addresses => all references must be updated
Some garbage collectors compact the heap automatically (see later)

28

Compaction
Requires 2 traversals of the heap and 1 traversal through all pointers
10

70

130

heap
pointers

1. For every block, compute its address after compaction


10
0
0

70
30
30

130
50

allocated blocks must have an


extra space to store the new
address.

50

2. Modify all pointers so that they point to the new address


0

10
0

30

50

70
30

130
50

problem: where are the pointers?


They can be in local variables or in
other objects.

3. Move blocks to their new address


0
0

30
30

50
50

29

Compaction with master pointers


block size
20

Pointers reference blocks via master pointers


(e.g. "handles" on the Macintosh)

30

master pointers
pointers

Step 1: Reverse master pointers

master[]

20 30

Step 2: Compact
20

30

master[]

Every block is referenced by just a single


master pointer

for (all elements i in master) {


p = master[i];
master[i] = p.len;
p.len = i;
}

a = heapStart;
for (all blocks p) {
if (p.used) {
i = p.len; p.len = master[i]; master[i] = a;
move block p to a;
a = a + p.len;
}
}

+ requires only 2 instead of 3 traversals


+ blocks do not need extra space to store their new address
- indirect access via master pointers is slower than direct access via pointers

30

You might also like