Download as pdf or txt
Download as pdf or txt
You are on page 1of 31

Chapter 7

Memory Management
This is an adapted version of portions of the text A Practical Approach to Operating
Systems (2nd ed), by Malcolm Lane and James Mooney. Copyright 1988-2011 by
Malcolm Lane and James D. Mooney, all rights reserved.

Revised: Mar. 28, 2011

7.1 INTRODUCTION
Managing the memory resources of a computing system for most effective use by its
application programs is the responsibility of memory management. This problem is concerned
chiefly with managing the main memory of the system, although it will have some concern with
secondary memory as well. The main memory resource is known by many names, including
primary storage, real storage, main storage, internal memory. Main memory is also referred to as
core because, in early systems, most main memories were physically constructed from tiny
magnetic rings known as cores. In this text we will sometimes use the terms memory and storage
interchangeably, but we will usually refer to the principal memory resource as main memory.

The problem of main memory management is composed of three principal subproblems:

• allocation, the problem of assigning suitable storage space to processes as


required. An efficient memory allocation mechanism may be expected to respond
quickly to requests for assorted amounts of memory, to assign memory only when
needed, and to reclaim memory promptly when its use is complete.

• relocation, the problem of matching programs and data to the memory locations
that have been allocated. In some cases, modifications must be made to addresses
in machine instructions and data to reflect the addresses actually used.

• protection, the problem of restricting a process's access to memory that has


actually been allocated to it. This problem cannot be solved by privileged
instructions, but must be addressed by other means.

The evolution of memory management techniques was shaped very much by the resource's
characteristics in the early days of computing. Memory was expensive and slow, and only very
limited amounts were available in most computers. Multiprogramming evolved partly because of
the need to share such expensive resources among several concurrent processes. With the
tradeoff available between cost, size, and speed, hierarchical memory systems were developed.

Because of the intensity of memory usage by operating systems and application processes,
full control of this resource is not possible without assistance from hardware mechanisms. In

-1-
Lane & Mooney Chapter 7: Memory Management

most computing systems today, the most effective memory management systems make use of
advanced hardware translation concepts, including paging, segmentation, and virtual memory.
These concepts, and the OS techniques that use them, will be discussed in detail in a later
chapter. This chapter focuses on memory management strategies that require more limited, if
any, hardware assistance. These techniques have been widely used in past systems, and are still
appropriate in small systems and specialized contexts where hardware translation is not available
or desirable.

7.2 SIMPLE ALLOCATION


Memory allocation refers to the action of selecting and reserving particular parts of
memory for use by particular processes. Usually memory is allocated in discrete blocks or
regions that must be contiguous; that is, they must occupy consecutive addresses in the logical
address space or virtual address space of the process (the addresses as seen by the programmer).
Since early operating systems allocated space in physical memory with little or no hardware
assistance, these operating systems were actually concerned with the allocation of contiguous
areas of this limited physical memory. In such an environment, operating systems may support a
wide variation of memory allocation strategies, from very simple to very complex. This section
considers the very simplest strategies; more complex strategies are examined in following
sections.

No Allocation

Certainly the simplest allocation strategy is none at all. With this approach, possible only
on systems that run a single program at a time, each program has total access to all portions of
memory and can manage it and use it in any manner (see Figure 7-1). While this is a simple
approach that costs nothing to implement because it entails no operating system service, the
disadvantage is precisely that no services are offered from the operating system. Programs can
use all memory, including that formerly occupied by the OS. It is the program's responsibility to
reload the OS when it completes. This technique, sometimes called the "bare machine" approach,
was used heavily in the early days of computing. Today it is restricted primarily to applications
that do not require a true OS, especially some real-time applications.

-2-
-
Lane & Mooney Chapter 7: Memory Management

Figure 7-1: A Bare Machine with No Memory Allocation

Single-user Operating Systems

The simplest type of operating system is one that serves only a single user and runs only
one process at a time. Allocation of memory in this type of OS is usually simple: a program may
use whatever memory it needs as long as the required memory exists and is not needed by the OS
itself. This approach is shown in Figure 7-2. Memory in such systems is viewed as being divided
into two areas, one for the operating system and one for the application program.

The placement of the resident monitor in memory can be in either high or low memory
addresses, or both. Many systems use low memory for the resident monitor, at least in part,
because this region contains locations with special built-in properties, such as interrupt vectors.
This is the view taken in Figure 7-2. Many single-user operating systems use such a placement
strategy for the resident monitor.

-3-
-
Lane & Mooney Chapter 7: Memory Management

Figure 7-2: Memory Allocation in a Simple Single-User System

Even though it is necessary for the OS to control special hardware locations in low
memory, the OS itself may be located in high memory. This is illustrated by the memory layout
of MS-DOS. This OS places the resident monitor in high memory, but reserves the lowest
memory addresses for interrupt vectors and other control information as shown in Figure 7-3. A
similar strategy was used by many early systems, including CP/M and RT-11.

Protecting the Nucleus

In a sense, allocation is only meaningful when accompanied by protection. Some


mechanism should exist to prevent a process's access to unallocated locations. Such protection is
only possible with hardware mechanisms not found on the simplest minicomputers or
microprocessors. However, many simple single-user operating systems are implemented on
computers without any provision for hardware protection of the nucleus or other unallocated
space. Since these are single-user systems, the problem is considered less serious; destruction of
the nucleus would only affect the work being done by one person. The single user operating
systems RT-11, CP/M, and MS-DOS, as examples, as well as the Macintosh OS, all lack any
type of memory protection.

-4-
-
Lane & Mooney Chapter 7: Memory Management

Figure 7-3: Memory Allocation in the Middle of Memory

In most newer architectures, protection is obtained as part of a comprehensive memory


translation mechanism. However, some older systems provide limited protection using simpler
hardware. We discuss these techniques in a later section.

7.3 ALLOCATION FOR MULTIPROGRAMMING


The strategies used in the simplest operating systems are only concerned with a single
program that occupies all or part of memory. Multiprogramming operating systems require that
memory be shared among two or more processes. Thus, portions of the memory must be chosen
for allocation to each process.

Static vs. Dynamic Allocation

A simple approach for allocating memory to processes in a multiprogrammed system is


static allocation. With this method, when each process is loaded and started, it is assigned all the
memory it is expected to require; it cannot be loaded until sufficient memory is available. The
process keeps all its memory throughout its lifetime but cannot obtain more. Static allocation is
simple to manage but does not allow effective sharing of memory in a multiprogrammed system.

For more efficient memory usage, a dynamic allocation strategy is required. With this
approach, each process is permitted to request additional memory as needed during execution,
and is expected to release memory it no longer needs. The operating system is presented with an
unpredictable sequence of allocate and free requests to assign and release individual blocks of
memory. The requested blocks may vary widely in size. Usually, each request must be filled by a
single contiguous region to be made available in the address space of the requesting process.

-5-
-
Lane & Mooney Chapter 7: Memory Management

Early Environments

As late as the mid-sixties, the size of the memory to be shared by all users of a system was
often only 512K bytes to 1 megabyte, even on large computers. The cost of such amounts of
memory was often in the hundreds of thousands of dollars. Management of this resource
included allocation to a particular process, placement and loading of programs, protection of
memory areas (if possible), and freeing of memory upon termination of a process. Since the
resource was so expensive, efficient utilization of memory was extremely important.

Most early multiprogramming operating systems only allowed a process to be allocated one
contiguous block in memory. Because of this, we shall assume use of static memory allocation
for the remainder of this section, as we present strategies for an OS's definition and tracking of
available memory to be allocated for loading a process.

Defining Memory Available for Allocation

Obviously, only a fixed amount of (physical) memory is available for allocation to


processes by an operating system. An OS can use two strategies for defining how many and what
size memory blocks can be assigned to processes being loaded:

• static memory area definition, in which the number of blocks and the size of
each block is defined when the operating system is loaded (or perhaps when it
was generated). The number of blocks available for loading processes does not
change once the OS loads.

• dynamic memory area definition, in which the OS determines the number of


blocks and the size of blocks upon servicing a request for memory allocation for
loading a process. The current state of memory---both allocated and free---
determines whether a block can be defined and allocated, and where it is located.
After the operating system is loaded, free memory is viewed as a "pool" in which
memory blocks can be defined for allocation to a process to be loaded.

We shall refer to memory blocks defined and allocated in a static memory area definition
environment as fixed partitions, or simply partitions. We shall refer to memory blocks defined
and allocated to processes in a dynamic memory area definition environment as regions.

Assuming a multiprogramming operating system uses static allocation and either static or
dynamic memory area definition, several possibilities exist for loading programs into memory:

• Several processes can share memory, each being allocated the same amount of
space using statically-defined fixed partitions. There is a fixed maximum number
of processes.

-6-
-
Lane & Mooney Chapter 7: Memory Management

• Several processes can share memory, each being allocated different amounts of
space using statically-defined fixed partitions. Again, there is a fixed maximum
number of processes.

• Several processes can share memory, each being allocated different amounts of
space using a variable number of variable-size regions. Here the number of
processes may have no fixed maximum.

Statically Defined Partitions

A fixed memory partition strategy divides all available space into a fixed number of
partitions. This strategy is common in real-time systems because a fixed number of real-time
processes are usually run in such environments. The partitions do not have to be all the same
size, but each has a fixed size established when the OS is first loaded and initialized. In some
early systems, each program had to be written to run in a specific partition; it could run in no
other. More powerful systems included methods for program relocation (to be discussed below).
These methods allowed programs to run in any partition large enough to hold them.

Figure 7-4 illustrates how memory is partitioned in a fixed partition system. In this
example, five partitions allow up to five processes to execute concurrently. Memory allocated to
a process that is not needed by that process is wasted. Also, if no programs can fit in the smaller
partitions, they are not used.

The use of fixed partitions greatly simplifies memory management. The operating system
only has to keep track of whether a partition is free or allocated, and update its data structures
after allocation to reflect the process using the partition.

Disadvantages of fixed partitions include the fact that the number of processes that can run
is fixed, and unused memory at the end of each partition is wasted. Thus, the very strategy used
to partition memory actually wastes a good portion of it because not all processes can use all the
memory available in the partitions assigned to them.

-7-
-
Lane & Mooney Chapter 7: Memory Management

Figure 7-4: A Fixed Partition Environment

Dynamically Defined Regions

In a strategy allowing the dynamic definition of a variable number of variable-size memory


regions, each region is defined at the size required and allocated by the operating system as
needed. The number of concurrent processes becomes variable depending on the number of
regions available at a given time. This strategy is illustrated in Figure 7-5. Control blocks are
used to keep track of regions allocated to processes, and of free memory. Unlike the control
blocks required for fixed partitions, which remain fixed in number, these control blocks must be
created dynamically by the operating system.

-8-
-
Lane & Mooney Chapter 7: Memory Management

Figure 7-5: A Variable Partition Environment

Allocation based on dynamically-defined regions has been used by a number of popular


OSs, including early versions of OS/360 (MVT), as well as the early Macintosh OS and some
versions of Windows.

A dynamically defined region strategy is a cross between the static and dynamic methods.
From the viewpoint of an individual process, the allocation is static. The space assigned to each
process is determined when the process starts, and does not change until the process completes.
However, the OS must take a dynamic viewpoint, as it deals with many processes of different
sizes that must start and complete at unpredictable times. Thus, this method includes many of the
problems of the full dynamic allocation to be discussed in the next section.

Figure 7-6 shows the dynamic allocation of memory regions to different processes over a
period of time. Initially there are 360K bytes of memory free. A process P1 requiring 120K is
selected for execution, as shown in the figure. Then a process P2 requests a 60K region and
begins execution. Process P3, requiring 120K, is loaded and executed, leaving a 60K block
remaining. The next process to be executed, P4, requires 120K of memory and must wait.
Process P2 terminates and 60K bytes are freed. There are now 120K bytes of free memory, but it
is not contiguous, so process P4 still must wait. This illustrates a major problem that can occur in
dynamic region definition and subsequent allocation: the problem of fragmentation, a term
describing the gradual division of free memory into many separate small sections that are not
large enough to meet the needs of most processes waiting to be loaded. Fragmentation may also
be used to describe the wasted space (that which is allocated to a process, but is never used by
the process) within a fixed memory partition.

-9-
-
Lane & Mooney Chapter 7: Memory Management

Figure 7-6: Fragmentation in Variable Space Allocation

7.4 DYNAMIC ALLOCATION


Operations and Data Structures

The principal operations involved in dynamic memory allocation are allocate and free.
These operations, each invoked by a system call at the program interface, form the basis of a
dynamic memory management strategy called heap management. Available memory is viewed
as a collection of blocks of random sizes that will be allocated and freed in an unpredictable
order. Dynamic heap management is a useful programming strategy that is discussed in many
texts on advanced programming and data structures. Here we review some basic concepts and
place the subject in an operating system context.

The allocate call presents the OS with a request for a specific amount of memory. Usually
there is no requirement that the allocated memory be in a specific place, but it is necessary that it
be contiguous. The OS must locate a suitable region of memory and make it available in the

-10-
-
Lane & Mooney Chapter 7: Memory Management

address space of the requesting process. If no suitable region is available, the process must wait
until the request can be fulfilled.

The free operation is used by a process to release blocks no longer needed. Usually each
allocated block must be freed in its entirety. The operating system must reclaim the freed blocks
and make them usable for later allocation requests. Any remaining unfreed space belonging to a
process is reclaimed when that process terminates.

Memory Control Blocks. Just as processes are represented by process control blocks, blocks of
memory, whether allocated or free, are described by memory control blocks (MCBs). Such
control blocks are given different names by different operating systems. For the sake of example,
we will call control blocks representing free memory free memory control blocks (FMCBs).
Those representing allocated storage will be called allocated memory control blocks
(AMCBs). Free memory space is then represented by a linked list of FMCBs usually maintained
in one (or both) of two orders: by decreasing size, and/or by increasing memory address.

FMCBs and AMCBs may be stored in a system control block area that is separate and
protected, similar to PCBs. Alternately, each may be a part of the corresponding storage block
itself, most conveniently placed as a header at the beginning of the block. This approach neatly
solves the problem of allocating the control blocks, since space is always available in each
distinct storage block. This method of organizing FMCBs and AMCBs is illustrated in Figure 7-
7.

A method devised by Knuth [1973], called the boundary tag method, places at the end of
each storage block an additional control block that contains the size of the block and an
indication of whether the block is free or allocated. A similar indication of whether the block is
free or allocated is placed in the beginning of the storage block, along with the size and
appropriate pointers to the next and previous FMCBs. This method provides some
simplifications in combining adjacent blocks as they are freed because adjacent blocks can be
easily checked to see if they are allocated or free by simply checking these boundary tags (which
are physically located immediately before and after a block of memory being freed).

-11-
-
Lane & Mooney Chapter 7: Memory Management

Figure 7-7: Memory Control Blocks

-12-
-
Lane & Mooney Chapter 7: Memory Management

Bit Maps. Another approach to keeping track of free and allocated memory is the use of bit
maps. This method is suitable when memory is considered to be partitioned into blocks of equal,
fixed size. Each block is represented by a bit, and the value of the bit indicates whether the block
is free or allocated (0 means free, 1 means allocated). Allocation of memory is done in multiples
of these fixed-size blocks. Figure 7-8 illustrates this representation of free and allocated blocks
of memory. The block size is assumed to be 1K bytes. The first three bits in the map indicate that
the first 3 blocks are allocated to Process 1, while the fourth and fifth bits of the map indicate
that the fourth and fifth blocks of memory are free, and so on. Note that the bit map does not
identify what process each block is assigned to; it only indicates that the units are allocated. The
address and size of the memory allocated must be stored in or linked to the PCB so that when a
process terminates, the appropriate bits in the bit map can be set back to zero to indicate these
memory units are now free.

Figure 7-8: Memory Management Using Bit Maps

Allocation Strategies

Any memory management system supporting dynamic allocation of variable-size blocks


must include a strategy for choosing the locations to be allocated in response to each request. If
several distinct free memory blocks are large enough to fulfill the request, which of them should
be chosen, and how should memory be divided to perform the allocation? Several strategies can
be used to choose a suitable block. Each has certain advantages and disadvantages. We will
discuss each of these strategies in the following sections.

-13-
-
Lane & Mooney Chapter 7: Memory Management

First-fit. The first allocation strategy to be considered is called first-fit. We have already seen
this strategy in the example of Figure 7-6. The first-fit method examines each FMCB starting
from the beginning of the list (usually the lowest address), and selects the first one large enough
to fulfill the request. Generally, the selected block is then divided into two parts. A portion large
enough to fulfill the request is allocated; the remainder is returned to the FMCB. The mechanism
for dividing blocks is considered in more detail below.

The first-fit strategy is appealing because it is simple and fast. However, it will often fulfill
a small request from a large area, leading to the rapid breakdown of large blocks. When a larger
area is later required, it may not be available as a contiguous block. Tests by Knuth [1975]
indicate that there is a tendency for small, rather useless blocks to collect at the front of the list
because all requests begin searching at the front of the list. Larger blocks will generally be found
near the end of the list.

Next-fit. A variation of the first-fit strategy is called next-fit. This strategy is similar to first-fit
except that it begins each search where the previous search ended (that is, the place where the
last block was allocated). A "roving pointer" to the list is maintained to remember where to begin
the next search. The list is treated as a circular list, so the pointer returns to the beginning after
the last FMCB is examined. If the pointer returns to the place where it began, the request cannot
be fulfilled. This strategy is illustrated in Figure 7-9.

Figure 7-9: The Next-fit Allocation Strategy

-14-
-
Lane & Mooney Chapter 7: Memory Management

The next-fit strategy eliminates some of the problems of the first-fit strategy because small
blocks do not tend to collect at the beginning of the list. The memory is used more evenly.
However, large blocks do not tend to remain at the end of the list, and this strategy may be less
likely to keep very large blocks available when needed.

Best-fit. Neither strategy discussed above considers the size of the block selected. The best-fit
strategy, by contrast, examines all free blocks and chooses the one whose size most closely
matches the request. This requires a search for the one best-fitting block; this search can be much
more efficient if the FMCBs are linked together in order of size.

The best-fit strategy is attractive because it wastes the smallest amount of memory for each
allocation. However, the leftover portions from each block tend to be very small and therefore
probably useless. The best-fit strategy is illustrated in Figure 7-10.

Figure 7-10: The Best-fit Allocation Strategy

Worst-fit. A worst-fit strategy selects the block that yields the largest remainder after it is
divided. In other words, it always allocates from the largest block available. To support this
method, the FMCBs should be linked in descending order by size. The worst-fit strategy is
depicted in Figure 7-11.

-15-
-
Lane & Mooney Chapter 7: Memory Management

While this strategy may seem foolish, it does have the advantage of producing leftovers
that are likely to be large enough to still be useful. However, the largest blocks always get
consumed first, and large blocks will probably not be available when required.

Figure 7-11: The Worst-fit Allocation Strategy

Making a Choice. The arguments above suggest that there are advantages and disadvantages to
all of these allocation strategies. Which one should be chosen? A useful measure of an allocation
strategy is how long it takes to block---that is, to be unable to meet a request because of
insufficient memory available in one piece. Unfortunately, the future sequence of allocate and
free operations is unknown, and sequences can be devised to make any one of these strategies
into winners or losers. Regardless of the strategy chosen, fragmentation and eventual blockage
are almost inevitable. When blockage does occur, it must be resolved by some type of drastic
action (Two possible solutions, swapping and compaction, are discussed in the last section of this
chapter.).

The behavior of actual systems has been studied extensively for various allocation
strategies. These studies tend to show that the two first-fit strategies, and the best-fit strategy,
have about equal track records for postponing blockage in general-purpose applications. Because

-16-
-
Lane & Mooney Chapter 7: Memory Management

first-fit is the simplest to implement, it is most often chosen, but next-fit and best-fit are
frequently used as well.

Dividing Free Blocks

As previously noted, the free block chosen for an allocation request will usually be larger
than required; as a result, the block is normally split into two parts: one to be allocated, and a
remainder to be returned to the free list. If the remainder block is very small, however, it may be
of little use as an independent free block. Since such a block can be useful only when it is
rejoined to a neighbor, the memory manager may choose not to split the block if the remainder is
less than some minimum size. Instead, the original block is kept intact, and the extra space is
unused temporarily until the block is released. When a free operation is performed on the block,
the entire block rejoins the free list. This approach may be especially desirable with a best fit
strategy, since remainder blocks tend to be very small.

Still another strategy may be to limit the ways in which blocks can be divided. In the well-
known buddy system, for example, each block must be used intact or divided exactly in half. If
a block is divided, the two halves are considered "buddies." A free block may combine only with
its buddy to form a larger block.

Recovering Memory Blocks After Use

A heap manager relies on the use of free operations by programs to return storage blocks to
the system when they are no longer needed. These blocks must then be returned to the free list in
a way that makes them as useful as possible for future allocations. Freeing memory could be as
simple as removing the block's MCB from the allocated list and adding it to the free list.
However, you should take an important additional step to make these blocks as useful as
possible. That step is to recognize when blocks of memory in the free list are adjacent to each
other, and combine them into a single larger block. Two steps in combining blocks are:

1. Recognize when a newly freed block is adjacent to other free blocks on either
side.

2. Merge the block with either or both adjacent neighbors, forming a single new
block with a single FMCB.

If the linked list of free memory blocks is ordered by increasing memory address, then it is
possible to determine when adjacent blocks are being freed by computing the beginning of the
next block from the current FMCB and checking to see if the next FMCB points to that address.
The boundary tag method also makes adjacent free blocks easy to detect.

If the FMCBs are organized as a list, it is a simple matter to remove a sequence from the
list and replace it with a single new one. The new control block must describe the newly
expanded memory block that previously was represented by two or three MCBs.

-17-
-
Lane & Mooney Chapter 7: Memory Management

Relocatable Blocks

Fragmentation in a heap would be less of a problem if blocks in use could be freely moved.
In this case several small free blocks could be converted to one larger one by moving the blocks
that separate them. However, memory blocks that are in use normally cannot be moved because
it would be impossible to locate all the pointers and address references which would have to be
changed.

A novel approach used for heap management introduced by the Macintosh OS provides the
possibility of relocatable blocks in the heap if a careful discipline is followed. This discipline
requires the creation of a single master pointer to the block (which is itself located in the heap).
All other references to the block are made indirectly through the master pointer. If the block is
moved, only the master pointer must change. The pointer, however, cannot be moved. A typical
Macintosh heap contains a mixture of relocatable blocks of this type and ordinary, non-
relocatable blocks.

This strategy may require some complex programming. Whereas most OSs support only a
few memory management operations such as allocate and free, the Macintosh OS provides over
two dozen operations for basic memory management.

Performance Considerations

The object of an effective memory manager is to perform allocate and free operations in a
manner that is fast and reliable and makes the most effective use of all available storage. The
allocation strategies discussed are reasonably fast and economical of storage. Best-fit is slower if
a search is required, but can be made quite fast if FMCBs are linked in order by size.

Besides performing both allocate and free operations efficiently, the memory manager
must also work to avoid fragmentation and blockage. This art can be accomplished only by a
judicious choice of control block forms and linking strategies, allocation strategies, and methods
for dividing and combining blocks. Although the problems are old, new strategies continue to be
devised. For example, a method called "fast fits" is reported by Stephenson [1983]. This method
combines FMCBs in a special tree structure rather than linear lists, providing some of the speed
advantages of the buddy system without a similar amount of wasted space.

7.5 RELOCATION METHODS


Most multiprogramming operating systems and many single-user operating systems allow
programs to be loaded into memory areas that may differ on each execution or may not have
been determined at the time the program was written. Because a program contains references to
memory locations in both its instructions and its data, correct operation may require that those
references be adjusted to reflect the actual locations being used. The process of adjusting a
program so it can run at the memory locations in which it is loaded is called relocation. If

-18-
-
Lane & Mooney Chapter 7: Memory Management

relocation is performed at the time a program is loaded or before, it is called static relocation. If
it can be achieved after the program has been loaded and begun execution, we call it dynamic
relocation. Relocation may be achieved by either software or hardware methods.

Programs may be relocated by software means if you can determine which references
should be changed and in what way when the actual memory addresses are known. In order to
identify these references, the object file produced by compilers or assemblers may include a
relocation dictionary which identifies all instructions and addresses that may need to be
modified depending on where the program is loaded. This object file is then converted to an
executable file by a relocating linker, or processed when loaded into memory by a relocating
loader. This relocating software makes adjustments to the appropriate memory references as
identified by the relocation dictionary so that they correspond to the actual locations in (virtual)
memory. The translation is illustrated in Figure 7-12.

Relocating software can be time consuming to use, requiring significant extra information
to be maintained in the object files. Since the relocation information is not loaded into memory
with the program, no further relocation is possible once the program has been loaded. Thus, this
strategy is able to provide only static, not dynamic, relocation. To achieve dynamic relocation
and limit the other problems cited, some type of hardware assistance is required, as described
below.

Figure 7-12: Program Relocation by a Relocating Loader

-19-
-
Lane & Mooney Chapter 7: Memory Management

Based Addressing

One type of hardware assistance for relocation, provided by the architecture of the IBM
S/360, is based addressing. In this method, a base register is maintained to represent the first,
or base address for the program. For each address reference in the machine instructions of the
program which specifies the use of based addressing, the effective address is formed by adding
the contents of the specified base register to the value in the address field (the displacement).
Relocation can be achieved with based addressing by loading this base register with the actual
starting address of the program. If it is necessary to move the program at a later time, the base
register may be changed to reflect the new location.

The effectiveness of based addressing in the S/360 was somewhat reduced because
instructions could only reference 4K bytes of memory at one time; thus, each 4K region required
a separate base register. Note also that based addressing requires that each instruction specify use
of the correct base register, and the technique is of no help in relocating address constants such
as pointers. However, the technique was quite helpful in the S/360 environment in alleviating
some of the problems of both static and dynamic relocation.

Relative Addressing

A variation on based addressing, exemplified by the PDP-11 and VAX, is the use of
relative addressing; this mechanism is essentially based addressing using the program counter
as a base register. Displacements contained in instructions which specify relative addressing are
displacements from the address of the instruction itself, and dynamic relocation can be
performed without the necessity of explicitly modifying the base register. Just as with based
addressing, effective use of this strategy requires a programming discipline to specify the correct
addressing technique for all memory references; this discipline is referred to as position-
independent coding.

Relocation Registers

As an improvement upon the base register concept, some computer systems have a
relocation register that is always added to every instruction address or data address before the
instruction or data is fetched by the CPU. Unlike the base register, the relocation register is used
uniformly for all memory references, and need not be specified by each instruction. Such a
register greatly simplifies relocation. In this case, programs that are designed to start at location 0
can be relocated to any address so long as this relocation register contains the address at which
the program is loaded. In such systems, the relocation register contents for each process must be
saved and restored via the PCB on a context switch. Figure 7-13 illustrates the use of a relocation
register.

-20-
-
Lane & Mooney Chapter 7: Memory Management

Figure 7-13: Use of a Relocation Register for Dynamic Relocation

-21-
-
Lane & Mooney Chapter 7: Memory Management

7.6 MEMORY PROTECTION


The object of memory protection is to prevent processes from accessing memory that was
not allocated for their use. Effective memory protection is impossible without hardware support.

In the simplest operating systems, as we have seen, memory is divided into two contiguous
regions, one for the OS and one for the program. Some computers provide a simple means of
checking if a user program reference is in the portion of memory reserved for the OS. This may
be done by establishing a fence address beyond which any memory references will cause a trap.
This fence address could be a fixed value, but it would be difficult to choose the value correctly.
If it were too large, unused memory would remain beyond the fence, inaccessible to applications;
if too small, not all of the operating system would be protected. An improved solution is a fence
register ,which can be set when the operating system is initialized (that is, when the resident
monitor is loaded). The use of a fence register to identify the boundary between the user program
and the resident monitor is illustrated in Figure 7-14. A fence may also be called a boundary,
and a fence register a boundary register.

Figure 7-14: Simple Protection Using a Fence Register

Bounds Registers

A fence register is insufficient to protect an OS such as MS-DOS or Windows, which have


portions in both high and low memory. A more general protection may be provided by a pair of
bounds registers. These registers provide both an upper and a lower bound on the memory
accessible to an application program. Use of bounds registers is illustrated in Figure 7-15.

Base and Limit Registers

The use of a limit register in conjunction with a base register is another technique for
providing memory protection. In this scheme, a variation of based addressing, the limit register

-22-
-
Lane & Mooney Chapter 7: Memory Management

represents the largest displacement that can be used. The displacement in each address field is
checked to ensure it is within this range. If it is, the value in the base register is added to the
displacement to dynamically relocate the reference (see Figure 7-16).

Figure 7-15: Use of Bounds Registers for Memory Protection

-23-
-
Lane & Mooney Chapter 7: Memory Management

Figure 7-16: Use of Base and Limit Registers for Memory Protection

Protection Keys

The final protection mechanism we will discuss is the use of protection keys. With this
mechanism, used in the IBM S/360 architecture, each 4K-byte block in memory is assigned a
protection key value between 0 and 15. In addition, selected blocks may be marked as "read
only." Each process is also assigned a protection key. When a process is selected to run, its key is
loaded into a special register. Any attempt to access a block of memory whose protection key
does not match the one currently in effect would result in a protection key violation interrupt,
and the program would be aborted (see Figure 7-17). Key 0 was assigned to the operating
system; if this key was loaded into the register, protection was effectively disabled. Note that this
mechanism limited the S/360 to 15 different protected regions, and that protection could be
specified only in units of 4K bytes.

While many models of the 360 computer supported memory read protection, OS/360 did
not make use of this protection. It only guarded against attempts to write to areas of memory not
assigned to a process. Hence, processes could read any other area of memory desired, including
sections of the operating system and other areas in use by other processes. Obviously, security in
these early systems fell short of the type of security needed today.

-24-
-
Lane & Mooney Chapter 7: Memory Management

Figure 7-17: Use of Protection Keys for Memory Protection

7.7 OTHER ISSUES


Overlays

Early single-user systems had limited memory available, often less than 64K bytes.
Execution of larger programs on such systems could be achieved only by dividing the program
into a series of overlays. Each overlay was a program unit, selected so that not all of them were
required to be present in memory at the same time; overlays that did not need to be in memory
together were assigned to the same region of memory, termed an overlay segment. Any overlay
segment to be shared by several programs at different instances in time had to be large enough to
hold the largest overlay in the group. Proper assignment of overlays and segments usually
required assistance from compilers and linkers.

To manage the loading of overlays, each program using this technique had to include a
control routine called an overlay supervisor which remained in memory at all times. This
supervisor was added to the program by the compiler or linker. When a program attempted to

-25-
-
Lane & Mooney Chapter 7: Memory Management

reference procedures or data in an overlay that was not currently loaded, the overlay supervisor
was invoked to fetch the required unit and load it into the specified overlay segment. Any
previously loaded overlay in that segment was destroyed (overlaid) by the new one. The use of
overlays is illustrated in Figure 7-18.

The overhead of loading overlays might seem high, but this technique allowed programs to
run in systems with limited memory, which could not have run if all modules had to reside in
memory at the same time. Overlay capability is still available in many systems today, in
particular on many microcomputers. However, it is no longer commonly used because memory
is now relatively inexpensive and not nearly so limited in size.

Swapping

For a variety of reasons you may need to remove portions of programs and their data from
the main memory before they are complete, with the expectation that they will finish at a later
time. The information so removed is placed on secondary storage until the time comes to return
it to main memory. This strategy is called swapping. We have discussed it also in connection
with process scheduling.

Swapping may be desired for a number of reasons:

• to remove a process that has been suspended by the medium-term scheduler

• to increase free memory if an allocation has been blocked

• to remove a process that is waiting for resources

• to prepare a process for movement to a new location, such as during compaction


(see below) or when its size is to be increased

Swapping of programs and data can be an effective management tool. However, each swap
must be scheduled and can be time consuming. This strategy adds overhead that can reduce the
frequency of process switching allowed.

To provide space for storage of swapped process, an area must be reserved on a fast storage
device, such as a disk. You can think of the process of reading and writing swapped data as a
special case of file creation and management.

-26-
-
Lane & Mooney Chapter 7: Memory Management

Figure 7-18: Use of Overlays to Reduce Program Size

Compaction

The collection of free space from multiple non-contiguous blocks into one large free block
in a system's memory is called compaction. This process is depicted in Figure 7-19. Systems
with no relocation register cannot use compaction (even if they support based addressing),

-27-
-
Lane & Mooney Chapter 7: Memory Management

because there is no way to ensure dynamic correction of all address constants, including those
contained in registers.

Systems with relocation registers, however, merely need to adjust the relocation register
contents for each process via the PCB. Storage compaction takes place periodically when used,
and can adversely affect performance because all process dispatching must cease while it is
taking place. Also, no I/O operations may be underway during compaction, because the data
addresses being used for I/O would be changed.

Figure 7-19: Compaction of Storage

SUMMARY
Memory management is the activity of managing the available memory for use by each
process. It involves three main problems: allocation, the assignment of memory to processes as
needed; relocation, the adjustment of programs and data to work in the assigned locations; and
protection, the restriction of access by processes to memory locations which have been allocated
to them.

In simple single-user systems, allocation may consist of giving each program free access to
all memory, and relocation and protection are usually absent. Simple multiprogramming systems
may use static allocation, giving each process all required memory when first loaded. Dynamic
allocation uses memory more effectively but requires use of heap management techniques. These
include use of memory control blocks or similar data structures, and choice of a basic strategy

-28-
-
Lane & Mooney Chapter 7: Memory Management

such as first-fit or best-fit. Methods for dividing and merging blocks are also needed, and
mechanisms like boundary tag or buddy systems may be considered. Heap management
strategies inevitably lead to fragmentation and eventual blockage; the only solution lies in
hardware assisted strategies to be discussed later.

Relocation may be performed by software or hardware. Often it is carried out by relocating


loaders or linkers, aided by a relocation dictionary in the program's object code. Hardware
relocation may be performed by mechanisms such as based addressing, relative addressing, or
relocation registers.

Effective memory protection requires hardware mechanisms. Techniques that have been
used for this purpose include fence registers, bounds registers, and protection keys.

Other issues of importance in the discussion of memory management include overlays,


swapping, and compaction.

FOR FURTHER READING


Memory management is an important concern for many types of software systems, not only
operating systems. For this reason many of its issues are dealt with in general programming and
data structure texts. Thorough discussion is presented in the classic work by Knuth [1973]. A
few other examples include Augenstein and Tenenbaum [1979], Wirth [1976], and Beidler
[1982]. An OS text which provides a particularly effective discussion is Madnick and Donovan
[1974, Ch. 3].

Some specialized strategies for allocation are presented by Beck [1982], Stephenson
[1983], and Oldehoft and Allan [1985].

REVIEW QUESTIONS

1. Explain the difference between static and dynamic allocation of memory.

2. What are the advantages of using a bit map instead of memory control blocks to
track free memory? The disadvantages?

3. How would a doubly-linked list be used in linking free memory control blocks?
Are there any orderings in which the pointer to the previous FMCB might be
useful?

4. When are fixed partitions defined for an operating system?

5. How does a relocation register aid in minimizing the impact of memory


fragmentation problems?

-29-
-
Lane & Mooney Chapter 7: Memory Management

6. What techniques can we use to simplify combining adjacent free blocks into one
single free block when a block of memory is freed?

7. How do memory allocation strategies affect performance?

8. Explain the purpose of a relocating loader. Where is it likely to reside in a


multiprogramming operating system? Why?

9. Explain the difference between systems using fixed partitions and (variable)
regions.

10. A comprehensive memory management system must include solutions to three


major problems. State and briefly define each problem, and explain how each
problem can be addressed in a system that provides no hardware assistance.

11. For each of the four strategies considered for selecting a free block for allocation,
describe the pattern of free blocks that tends to accumulate in the memory, and
give one argument in favor of that particular strategy.

12. In a variable-space memory management system, free blocks may be kept linked
together in two distinct orders at the same time. Identify each order and state its
purpose.

ASSIGNMENTS
1. Compare several techniques used for memory protection (without paging or
segmentation). Explain their principal advantages and disadvantages.

2. If a process is selected for swapping to disk, can it be reloaded into a different


location than that it occupied before it was swapped out? Explain what is
necessary to make this possible.

3. What are some disadvantages of allocating AMCBs in the storage block itself?

4. Review the literature and appropriate manuals to determine the format of memory
control blocks in an operating system of your choice. Explain the purpose of the
information they contain.

5. Identify an operating system that managed memory with little or no assistance


from the hardware and describe the techniques used.

-30-
-
Lane & Mooney Chapter 7: Memory Management

PROJECT
This section describes a two-part programming project to implement some dynamic
memory allocation mechanisms for a simple multiprogramming operating system. You should
read the general description in this text in conjunction with the more specific descriptions given
in your project manual. These mechanisms are important components of the multiprogramming
executive (MPX) project.

a. Add a set of commands to the command handler COMHAN to simulate a first-fit


allocation scheme of a simulated area of memory. Use AMCBs and FMCBs to
represent memory areas. The required commands are:

1. MEMORY LIST ALL: display a formatted list of all memory areas.

2. MEMORY LIST FREE: display a formatted list of all free memory areas.

3. MEMORY LIST ALLOC: display a formatted list of all allocated memory


areas.

4. MEMORY FREE ALL: free all allocated memory.

5. MEMORY FREE addr : free the memory represented by the AMCB at the
address identified by addr .

6. MEMORY ALLOCATE size: allocate a memory block of a size specified by


size, displaying a return code indicating success or failure, and the address of
the AMCB for the memory allocated.

b. Implement a set of procedures that provide dynamic memory allocation for loading
processes. This support should include identification of a "pool" of free memory
from which memory can be allocated for PCBs, regions for loading processes, and
dynamic memory requests issued by a process. The following services are to be
provided for this dynamic memory allocation:

1. RC=Allocate(AMCB_address,memory_size): allocate a block of


the specified size. Return the address of the associated AMCB in the parameter
AMCB_address. RC is a return code that should receive a value of 0 if the
allocation was successful, or -1 if an error occurred.

2. RC=Free(AMCB_address): free the block indicated by AMCB_address


and provide an appropriate return code.

The memory management provided in this project is a low-level service that the operating
system can use both for allocating memory for itself (for both PCBs and process load areas) and
for processes making dynamic memory allocation requests.

-31-
-

You might also like