CS 474 - Memory Management

First, be aware that the text spends far, far too much time on early memory management schemes that, today, are of only historical interest. All the same, a brief survey of memory management history is worthwhile.

Memory management became necessary when we first started running multiple processes in a single computer. The basic problem was, given a program with a certain space requirement, how could we find space in the machine for the program? Early computer hardware provided absolutely no help at all; when a program was compiled and linked, it still had to be left somewhat incomplete - you couldn't have the target of a jsr instruction in the code, for instance, because you couldn't know where the program was going to end up being loaded. So the loader had the responsibility of finishing things up, putting in procedure and variable addresses and the like, as it started a program executing.

The first help that the hardware gave for memory management just made the loader's job easier by supporting position-independent code. The idea here is that the instruction set is designed so that the code can be loaded anywhere without modification, and will still work. For instance, using a PC-relative jsr instruction will work wherever in memory you put the program, since the distance the jsr has to cover is fixed. Even with position-independent code, once you've loaded the program into memory it (generally) can't move; you can't shuffle stuff around to make more efficient use of space. If you have no pointers in your data (like FORTRAN) your data can be moved around; you still have grief from return addresses in procedures, though.

Also, notice that neither of these schemes provide any memory protection: if a program has a bug, it can corrupt the data belonging to an entirely different process. I've heard that it was quite common to use negative array indexes in FORTRAN to modify the OS itself. Crackers have been around forever!

The next step came with the development of base registers: the code is not position-independent, but all memory references are effectively indexed. In the case of the CDC 6600, there was both a base register and a limit register; the program thought its available space went from 0 up to the limit set by the limit register. Trying to access memory above the limit would crash the program. Having a base register makes it possible to move a program around at run time to make better use of space, or even take it completely out of memory and put it back in later at a different place.

Fixed Memory Partitions vs. General Memory Management

A problem that exists whenever we want to try to put several processes in memory (and we don't have paging) is that we have to have memory management schemes. The simplest I can imagine is to use fixed partitions: we begin by dividing memory into a bunch of partitions (typically of different sizes). Now we'll be able to run small processes in small partions, larger ones in larger partitions, and so forth. From here, we can either queue processes up according to the partitions they can fit in, or else use a common queue for all of them. This scheme was used with OS/360.

A more flexible (and more complicated) scheme is to use general-purpose memory-management algorithms, with either free lists or bitmaps of free space. Now when we want to load a program, we have to find space to put it. Typically, there will be several free memory regions large enough for the new process; of the free blocks we can choose from, which is best? We end up being guided by trying to avoid fragmentation, a situation in which we may have enough memory available someplace in memory, but no individual blocks that are big enough to meet our needs. The primary responsibility of a memory management algorithm is that it avoid fragmentation. There are several policies in use; the major ones are best-fit, first-fit, next-fit, and worst-fit.

Very surprisingly, to me anyway, is that best-fit is a crummy choice. It turns out to leave lots of tiny, useless fragments of memory hanging around.

Worst-fit certainly avoids that problem! However, occasionally a request may come in for a really big memory block; worst-fit does its best to guarantee that there is no such big block free.

First-fit ends up creating a good distribution of available memory sizes; the smaller pieces tend to be near the front of the list and the larger pieces toward the end. Next-fit was intended to keep the small pieces from clustering like they do with first-fit, but ends up with the unfortunate side-effect of breaking up the really big pieces. Surprisingly, first-fit tends overall to be the best choice.

Overlays

An early discovery was that memory isn't big enough (I wouldn't be terribly surprised to learn that the first program ever written ran out of space). Users always needed more space for their programs than was available in the system; even if they didn't, they were charged for memory usage, so less was better.

A mechanism programmers used to get around memory limitations was called overlays. The idea here was that the programmer (or the compiler) would identify areas in the program that didn't depend heavily on each other. So if you've got a big numerical analysis program with a well-defined input phase, processing phase, and output phase, you probably didn't really need all three of them at once. So you'd build your program with four modules: the three we just talked about, which we'll call overlays, and a module called an overlay manager. The overlay manager is always in memory (at least, always when your program is running); calls between overlays are translated into calls to the overlay manager which will throw one of the other overlays out, and bring another one in. If you've done a good job of dividing your program up into overlays, it works really well: you have a little bit of time spent going between overlays, but you spend a lot less on memory (or it may make the difference between being able to run, and not being able to run). If you've done a bad job, it's a disaster: you can end up spending all your time going back and forth between the overlays.


Last modified: Mon Sep 26 11:10:34 MDT 2005