0% found this document useful (0 votes)
37 views

1.interprocess Communication Mechanisms 2.memory Management and Virtual Memory

The document discusses interprocess communication (IPC) mechanisms and memory management techniques in operating systems. It describes different IPC methods like message passing using pipes, message queues, and sockets. It also covers shared memory IPC and the need for synchronization primitives like semaphores, mutexes, and monitors when processes access shared memory. The document then discusses memory management techniques including virtual memory, paging, segmentation, and page replacement algorithms.

Uploaded by

Sri Vardhan
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
37 views

1.interprocess Communication Mechanisms 2.memory Management and Virtual Memory

The document discusses interprocess communication (IPC) mechanisms and memory management techniques in operating systems. It describes different IPC methods like message passing using pipes, message queues, and sockets. It also covers shared memory IPC and the need for synchronization primitives like semaphores, mutexes, and monitors when processes access shared memory. The document then discusses memory management techniques including virtual memory, paging, segmentation, and page replacement algorithms.

Uploaded by

Sri Vardhan
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 45

UNIT -IV

Interprocess Communication Mechanisms: IPC between processes on a single computer


system, IPC between processes on different systems, using pipes, FIFOs, message queues, shared
memoryimplementation in linux. Corresponding system calls.
Memory Management and Virtual Memory - Logical versus Physical Address
Space, Swapping, Contiguous Allocation, Paging, Segmentation, Segmentation with
Paging, Demand Paging, Page Replacement, Page Replacement Algorithms.

Inter Process Communication


 Processes share memory
o data in shared messages
 Processes exchange messages
o message passing via sockets
 Requires synchronization
o mutex, waiting

Inter Process Communication(IPC) is an OS supported mechanism for interaction among


processes(coordination and communication)

Message Passing
 e.g. sockets, pips, messages, queuesMemory based IPC
 shared memory, memory mapped filesHigher level semantics
 files, RPC Synchronization primitives

Message Passing

 Send/Receive messages
 OS creates and maintains a channel
o buffer, FIFO queue
 OS provides interfaces to processes
o a port
o processes send/write messages to this port
o processes receive/read messages from this port
 Kernel required to
o establish communication
o perform each IPC operation
o send: system call + data copy
o receive: system call + data copy
Request-response:4xuser/kernelcrossings+4x data copies

Advantages

 simplicity : kernel does channel management and synchronization

Disadvantages

 Overheads

Forms of Message Passing IPC


1. Pipes

 Carry byte stream between 2 process


 e.g connect output from 1 process to input of

another

2. Message queues

 Carry "messages" among processes 

79
 OS management includes priorities, scheduling of message delivery
 APIs : Sys-V and POSIX

3. Sockets

 send() and recv() : pass message buffers


 socket() : create kernel level socket buffer
 associated necessary kernel processing (TCP-IP,..)
 If different machines, channel between processes and network devices
 If same machine, bypass full protocol stack

Shared Memory IPC

 read and write to shared memory region


 OS establishes shared channel between the processes
1. physical pages mapped into virtual address space
2. VA(P1) and VA(P2) map to same physical address
3. VA(P1) != VA(P2)
4. physical memory doesn't need to be contiguous
 APIs : SysV, POSIX, memory mapped files, Android ashmem

80
Advantages

 System calls only for setup data cop ies potentially reduced (but not eliminated)

Disdvantages

 explicit synchronization
 communication protocol, shared bu ffer management
o programmer's responsibility

Overheads for 1. Message Passing : mu st perform multiple copies 2. Shared Memory : must establish all
mappings among processes' address space and shared memory pages

Copy vs Map
Goal for both is to transfer data from one into target address space

Copy (Message Passing) Map (Shared Memory)


CPU cycles to copy data CPU cycles to map memory into
to/from port address space
CPU to copy data to channel

If channel setup once, use many times


(good payoff)
Can perform well for 1 time use

 Large Data: t(Copy) >> t(Map)


o e.g. trade-off exercised in Window "Local" Procedure Calls (LPC)

Shared Memory and Synchronization


Use threads accessing shared state in a single addressing space, but for process

Synchronization method:

81
1. mechanism supported by processing threading library (pthreads)
2. OS supported IPC for sync

Either method must coordinate

 no of concurrent access to shared segment


 when data is available and ready for consumption

IPC Synchronization
Message Queues Semaphores
Implement "mutual
OS supported synchronization construct
exclusion" via send/receive
binary construct (either allow process or
not)
Like mutex, if value = 0, stop; if value =
1, decrement(lock) and proceed

Synchronization
Waiting for other processes, so that they can continue working togethermay repeatedly check to continue

o sync using spinlocks


may wait for a signal to continue
o sync using mutexes and condition vatiables
waiting hurts performance
o CPUs waste cycles for checking; cache effects
Limitation of mutextes and condition variables:
 Error prone/correctness/ease of use
o unlock wrong mutex, signal wrong condition variable
Lack of expressive power
o helper variables for access or priority control

Low-level support: hardware atomic instructions

Synchronization constructs:

1. Spinlocks (basic sync construct)


 Spinlock is like a mutex

82
 mutual exclusion
 lock and unlock(free)
 but, lock == busy => spinning
2. Semaphores
 common sync construct in OS kernels
 like a traffic light: Stop and Go
 like mutex, but more general

Semaphore == integer value

o assigned a max value (positive int) => max count


on try(wait)
o if non-zero, decrement and proceed => counting semaphore
if initialized with 1
o semaphore == mutex(binary semaphore)
on exit(post)
o increment

Syncing different types of accesses


Reader/Writer locks
read (don't modify) write (always modify)

shared access exclusive access

 RW locks

o specify type of access, then lock behaves accordingly

Monitors (highlevel construct)

 shared resource
 entry resource
 possible condition variables

On entry:

83
o lock, check
On exit:
o unlock, check, signal

More synchronization constructs

 serializers
 path expressions
 barriers
 rendezvous points
 optimistic wait-free sync (RCU) [Read Copy Update]

All need hardware support.

Need for hardware support

 Problem
o concurrent check/update on different CPUs can overlap

Atomic instructions
Critical section with hardware supported synchronization

Hardware specific
 Test-and-set

o returns(tests) original values and sets new-value!= 1 (busy) automatically


o first thread: test-and-set(lock) => 0 : free
o next ones: test-and-set(lock) => 1 busy
 reset lock to 1, but that's okay
o + : Latency
o + : minimal (Atomic)
o + : Delay potentially min
o - : Contention processors go to memory on each spin - To reduce contention, introduce delay -
Static(based on a fixed value) or Dynamic(backoff based, random delay)

84
read-and-increment
compare-and-swap

Guarantees

 atomicity
 mutual exclusion
 queue all concurrent instructions but one

Shared Memory Multiprocessors


Also called symmetric multiprocessors (SMP)

 Caches
o hide memory latency, "memory" further away due to contention

o no-write, write-through, write-back

Cache Coherence

85
What are system calls in Operating System?
The interface between a process and an operating system is provided by system calls. In general,
system calls are
available as assembly language instructions. They are also included in the manuals used by the
assembly level programmers. System calls are usually made when a process in user mode requires access to
a resource.
Then it requests the kernel to provide the resource via a system call.
A figure representing the execution of the system call is given as follows −

As can be seen from this diagram, the processes execute normally in the user mode until a system call
interrupts this. Then the system call is executed on a priority basis in the kernel mode. After the execution of
the system call, the control returns to the user mode and execution of user processes can be resumed.
In general, system calls are required in the following situations −

 If a file system requires the creation or deletion of files. Reading and writing from files also require a
system call.
 Creation and management of new processes.
 Network connections also require system calls. This includes sending and receiving packets.
 Access to a hardware devices such as a printer, scanner etc. requires a system call.
Types of System Calls
There are mainly five types of system calls. These are explained in detail as follows −
Process Control
These system calls deal with processes such as process creation, process termination etc.
86
File Management
These system calls are responsible for file manipulation such as creating a file, reading a file, writing into a
file etc.
Device Management
These system calls are responsible for device manipulation such as reading from device buffers, writing into
device buffers etc.
Information Maintenance
These system calls handle information and its transfer between the operating system and the user program.
Communication
These system calls are useful for interprocess communication. They also deal with creating and deleting a
communication connection.
Some of the examples of all the above types of system calls in Windows and Unix are given as follows −
Types of System
Windows Linux
Calls
CreateProcess() fork()
ExitProcess() exit()
Process Control
WaitForSingleObject() wait()

CreateFile() open()
ReadFile() read()
File Management
WriteFile() write()
CloseHandle() close()
SetConsoleMode() ioctl()
Device Management ReadConsole() read()
WriteConsole() write()
GetCurrentProcessID() getpid()
Information
SetTimer() alarm()
Maintenance
Sleep() sleep()
CreatePipe() pipe()
Communication CreateFileMapping() shmget()
MapViewOfFile() mmap()
There are many different system calls as shown above. Details of some of those system calls are as follows

open()
The open() system call is used to provide access to a file in a file system. This system call allocates
resources to the file and provides a handle that the process uses to refer to the file. A file can be opened by
multiple processes at the same time or be restricted to one process. It all depends on the file organisation and
file system.
read()
The read() system call is used to access data from a file that is stored in the file system. The file to read can
be identified by its file descriptor and it should be opened using open() before it can be read. In general, the

87
read() system calls takes three arguments i.e. the file descriptor, buffer which stores read data and number of
bytes to be read from the file.
write()
The write() system calls writes the data from a user buffer into a device such as a file. This system call is
one of the ways to output data from a program. In general, the write system calls takes three arguments i.e.
file descriptor, pointer to the buffer where data is stored and number of bytes to write from the buffer.
close()
The close() system call is used to terminate access to a file system. Using this system call means that the file
is no longer required by the program and so the buffers are flushed, the file metadata is updated and the file
resources are de-allocated.

Main Memory
Background

 Obviously memory accesses and memory management are a very important part of modern computer
operation. Every instruction has to be fetched from memory before it can be executed, and most instructions
involve retrieving data from memory or storing data in memory or both.
 The advent of multi-tasking OSs compounds the complexity of memory management, because as
processes are swapped in and out of the CPU, so must their code and data be swapped in and out of memory,
all at high speeds and without interfering with any other processes.
 Shared memory, virtual memory, the classification of memory as read-only versus read-write, and
concepts like copy-on-write forking all further complicate the issue.

Basic Hardware

 It should be noted that from the memory chips point of view, all memory accesses are equivalent.
The memory hardware doesn't know what a particular part of memory is being used for, nor does it care.
This is almost true of the OS as well, although not entirely.
 The CPU can only access its registers and main memory. It cannot, for example, make direct
access to the hard drive, so any data stored there must first be transferred into the main memory chips
before the CPU can work with it. ( Device drivers communicate with their hardware via interrupts and
"memory" accesses, sending short instructions for example to transfer data from the hard drive to a
specified location in main memory. The disk controller monitors the bus for such instructions, transfers
the data, and then notifies the CPU that the data is there with another interrupt, but the CPU never gets
direct access to the disk. )
 Memory accesses to registers are very fast, generally one clock tick, and a CPU may be able to
execute more than one machine instruction per clock tick.
 Memory accesses to main memory are comparatively slow, and may take a number of clock ticks
to complete. This would require intolerable waiting by the CPU if it were not for an intermediary fast
memory cache built into most modern CPUs. The basic idea of the cache is to transfer chunks of memory
at a time from the main memory to the cache, and then to access individual memory locations one at a
time from the cache.
 User processes must be restricted so that they only access memory locations that "belong" to that
particular process. This is usually implemented using a base register and a limit register for each process,
as shown in Figures 3.1 and 3.2 below. Every memory access made by a user process is checked against
these two registers, and if a memory access is attempted outside the valid range, then a fatal error is
generated. The OS obviously has access to all existing memory locations, as this is necessary to swap
88
users' code and data in and out of memory. It should also be obvious that changing the contents of the base
and limit registers is a privileged activity, allowed only to the OS kernel.

Figure 4.1 - A base and a limit register define a logical addresss space

Figure 3.2 - Hardware address protection with base and limit registers

3.1.2 Address Binding

 User programs typically refer to memory addresses with symbolic names such as "i", "count", and
"averageTemperature". These symbolic names must be mapped or bound to physical memory addresses,
which typically occurs in several stages:
o Compile Time - If it is known at compile time where a program will reside in physical memory,
then absolute code can be generated by the compiler, containing actual physical addresses. However if the
load address changes at some later time, then the program will have to be recompiled. DOS .COM programs
use compile time binding.
o Load Time - If the location at which a program will be loaded is not known at compile time, then
the compiler must generate relocatable code, which references addresses relative to the start of the program.
If that starting address changes, then the program must be reloaded but not recompiled.

89
o Execution Time - If a program can be moved around in memory during the course of its execution,
then binding must be delayed until execution time. This requires special hardware, and is the method
implemented by most modern OSes.
 Figure 3.3 shows the various stages of the binding processes and the units involved in each stage:

Figure 4.3 - Multistep processing of a user program

Logical Versus Physical Address Space

 The address generated by the CPU is a logical address, whereas the address actually seen by the
memory hardware is a physical address.
 Addresses bound at compile time or load time have identical logical and physical addresses.
 Addresses created at execution time, however, have different logical and physical addresses.
o In this case the logical address is also known as a virtual address, and the two terms are used
interchangeably by our text.
o The set of all logical addresses used by a program composes the logical address space, and the set of
all corresponding physical addresses composes the physical address space.
 The run time mapping of logical to physical addresses is handled by the memory-management unit,
MMU.
o The MMU can take on many forms. One of the simplest is a modification of the base-register
scheme described earlier.
o The base register is now termed a relocation register, whose value is added to every memory request
at the hardware level.

90
 Note that user programs never see physical addresses. User programs work entirely in logical
address space, and any memory references or manipulations are done using purely logical addresses. Only
when the address gets sent to the physical memory chips is the physical memory address generated.

Figure 3.4 - Dynamic relocation using a relocation register

Dynamic Loading

 Rather than loading an entire program into memory at once, dynamic loading loads up each routine as
it is called. The advantage is that unused routines need never be loaded, reducing total memory usage and
generating faster program startup times. The downside is the added complexity and overhead of checking
to see if a routine is loaded every time it is called and then loading it up if it is not already loaded.

Dynamic Linking and Shared Libraries

 With static linking library modules get fully included in executable modules, wasting both disk
space and main memory usage, because every program that included a certain routine from the library
would have to have their own copy of that routine linked into their executable code.
 With dynamic linking, however, only a stub is linked into the executable module, containing
references to the actual library module linked in at run time.
o This method saves disk space, because the library routines do not need to be fully included in the
executable modules, only the stubs.
o We will also learn that if the code section of the library routines is reentrant, ( meaning it does not
modify the code while it runs, making it safe to re-enter it ), then main memory can be saved by loading
only one copy of dynamically linked routines into memory and sharing the code amongst all processes
that are concurrently using it. ( Each process would have their own copy of the data section of the
routines, but that may be small relative to the code segments. ) Obviously the OS must manage shared
routines in memory.
o An added benefit of dynamically linked libraries ( DLLs, also known as shared libraries or shared
objects on UNIX systems ) involves easy upgrades and updates. When a program uses a routine from a
standard library and the routine changes, then the program must be re-built ( re-linked ) in order to
incorporate the changes. However if DLLs are used, then as long as the stub doesn't change, the
program can be updated merely by loading new versions of the DLLs onto the system. Version
information is maintained in both the program and the DLLs, so that a program can specify a particular
version of the DLL if necessary.
o In practice, the first time a program calls a DLL routine, the stub will recognize the fact and will
replace itself with the actual routine from the DLL library. Further calls to the same routine will access

91
the routine directly and not incur the overhead of the stub access. ( Following the UML Proxy
Pattern. )

Swapping

 A process must be loaded into memory in order to execute.


 If there is not enough memory available to keep all running processes in memory at the same time,
then some processes who are not currently using the CPU may have their memory swapped out to a fast
local disk called the backing store.

Standard Swapping

 If compile-time or load-time address binding is used, then processes must be swapped back into the
same memory location from which they were swapped out. If execution time binding is used, then the
processes can be swapped back into any available location.
 Swapping is a very slow process compared to other operations. For example, if a user process
occupied 10 MB and the transfer rate for the backing store were 40 MB per second, then it would take
1/4 second ( 250 milliseconds ) just to do the data transfer. Adding in a latency lag of 8 milliseconds and
ignoring head seek time for the moment, and further recognizing that swapping involves moving old data
out as well as new data in, the overall transfer time required for this swap is 512 milliseconds, or over
half a second. For efficient processor scheduling the CPU time slice should be significantly longer than
this lost transfer time.
 To reduce swapping transfer overhead, it is desired to transfer as little information as possible,
which requires that the system know how much memory a process is using, as opposed to how much it
might use. Programmers can help with this by freeing up dynamic memory that they are no longer using.
 It is important to swap processes out of memory only when they are idle, or more to the point, only
when there are no pending I/O operations. ( Otherwise the pending I/O operation could write into the
wrong process's memory space. ) The solution is to either swap only totally idle processes, or do I/O
operations only into and out of OS buffers, which are then transferred to or from process's main memory
as a second step.
 Most modern OSes no longer use swapping, because it is too slow and there are faster alternatives
available. ( e.g. Paging. ) However some UNIX systems will still invoke swapping if the system gets
extremely full, and then discontinue swapping when the load reduces again. Windows 3.1 would use a
modified version of swapping that was somewhat controlled by the user, swapping process's out if
necessary and then only swapping them back in when the user focused on that particular window.

92
Figure 4.5 - Swapping of two processes using a disk as a backing store

Contiguous Memory Allocation

 One approach to memory management is to load each process into a contiguous space. The operating
system is allocated space first, usually at either low or high memory locations, and then the remaining
available memory is allocated to processes as needed. ( The OS is usually loaded low, because that is
where the interrupt vectors are located, but on older systems part of the OS was loaded high to make more
room in low memory ( within the 640K barrier ) for user processes. )

Memory Protection

 The system shown in Figure 3.6 below allows protection against user programs accessing areas that
they should not, allows programs to be relocated to different memory starting addresses as needed, and
allows the memory space devoted to the OS to grow or shrink dynamically as needs change.

Figure 3.6 - Hardware support for relocation and limit registers

Memory Allocation

 One method of allocating contiguous memory is to divide all available memory into equal sized
partitions, and to assign each process to their own partition. This restricts both the number of simultaneous
processes and the maximum size of each process, and is no longer used.
 An alternate approach is to keep a list of unused ( free ) memory blocks ( holes ), and to find a hole of
a suitable size whenever a process needs to be loaded into memory. There are many different strategies for
finding the "best" allocation of memory to processes, including the three most commonly discussed:
1. First fit - Search the list of holes until one is found that is big enough to satisfy the request, and
assign a portion of that hole to that process. Whatever fraction of the hole not needed by the request is left
on the free list as a smaller hole. Subsequent requests may start looking either from the beginning of the list
or from the point at which this search ended.
2. Best fit - Allocate the smallest hole that is big enough to satisfy the request. This saves large holes for
other process requests that may need them later, but the resulting unused portions of holes may be too
small to be of any use, and will therefore be wasted. Keeping the free list sorted can speed up the process of
finding the right hole.
3. Worst fit - Allocate the largest hole available, thereby increasing the likelihood that the remaining
portion will be usable for satisfying future requests.
93
 Simulations show that either first or best fit are better than worst fit in terms of both time and storage
utilization. First and best fits are about equal in terms of storage utilization, but first fit is faster.

4.3.3. Fragmentation

 All the memory allocation strategies suffer from external fragmentation, though first and best fits
experience the problems more so than worst fit. External fragmentation means that the available memory is
broken up into lots of little pieces, none of which is big enough to satisfy the next memory requirement,
although the sum total could.
 The amount of memory lost to fragmentation may vary with algorithm, usage patterns, and some
design decisions such as which end of a hole to allocate and which end to save on the free list.
 Statistical analysis of first fit, for example, shows that for N blocks of allocated memory, another 0.5
N will be lost to fragmentation.
 Internal fragmentation also occurs, with all memory allocation strategies. This is caused by the fact
that memory is allocated in blocks of a fixed size, whereas the actual memory needed will rarely be that
exact size. For a random distribution of memory requests, on the average 1/2 block will be wasted per
memory request, because on the average the last allocated block will be only half full.
o Note that the same effect happens with hard drives, and that modern hardware gives us increasingly
larger drives and memory at the expense of ever larger block sizes, which translates to more memory lost to
internal fragmentation.
o Some systems use variable size blocks to minimize losses due to internal fragmentation.
 If the programs in memory are relocatable, ( using execution-time address binding ), then the external
fragmentation problem can be reduced via compaction, i.e. moving all processes down to one end of
physical memory. This only involves updating the relocation register for each process, as all internal work
is done using logical addresses.
 Another solution as we will see in upcoming sections is to allow processes to use non-contiguous
blocks of physical memory, with a separate relocation register for each block.

Segmentation

Basic Method

 Most users ( programmers ) do not think of their programs as existing in one continuous linear
address space.
 Rather they tend to think of their memory in multiple segments, each dedicated to a particular use,
such as code, data, the stack, the heap, etc.
 Memory segmentation supports this view by providing addresses with a segment number ( mapped to
a segment base address ) and an offset from the beginning of that segment.
 For example, a C compiler might generate 5 segments for the user code, library code, global ( static )
variables, the stack, and the heap, as shown in Figure 4.7:

94
Figure 4.7 Programmer's view of a program.

Segmentation Hardware

 A segment table maps segment-offset addresses to physical addresses, and simultaneously checks for
invalid addresses, using a system similar to the page tables and relocation base registers discussed
previously. ( Note that at this point in the discussion of segmentation, each segment is kept in contiguous
memory and may be of different sizes, but that segmentation can also be combined with paging as we shall
see shortly. )

95
Figure 4.8 - Segmentation hardware

Figure 4.9 - Example of segmentation

Paging

 Paging is a memory management scheme that allows processes physical memory to be discontinuous,
and which eliminates problems with fragmentation by allocating memory in equal sized blocks known as
pages.
 Paging eliminates most of the problems of the other methods discussed previously, and is the
predominant memory management technique used today.

Basic Method

 The basic idea behind paging is to divide physical memory into a number of equal sized blocks called
frames, and to divide a programs logical memory space into blocks of the same size called pages.
 Any page ( from any process ) can be placed into any available frame.
 The page table is used to look up what frame a particular page is stored in at the moment. In the
following example, for instance, page 2 of the program's logical memory is currently stored in frame 3 of
physical memory:

96
Figure 4.10 - Paging hardware

Figure 4.11 - Paging model of logical and physical memory

 A logical address consists of two parts: A page number in which the address resides, and an offset
from the beginning of that page. ( The number of bits in the page number limits how many pages a single
process can address. The number of bits in the offset determines the maximum size of each page, and
should correspond to the system frame size. )
 The page table maps the page number to a frame number, to yield a physical address which also has
two parts: The frame number and the offset within that frame. The number of bits in the frame number
determines how many frames the system can address, and the number of bits in the offset determines the
size of each frame.
 Page numbers, frame numbers, and frame sizes are determined by the architecture, but are typically
powers of two, allowing addresses to be split at a certain number of bits. For example, if the logical
address size is 2^m and the page size is 2^n, then the high-order m-n bits of a logical address designate the
page number and the remaining n bits represent the offset.
 Note also that the number of bits in the page number and the number of bits in the frame number do
not have to be identical. The former determines the address range of the logical address space, and the
latter relates to the physical address space.

97
 ( DOS used to use an addressing scheme with 16 bit frame numbers and 16-bit offsets, on hardware
that only supported 24-bit hardware addresses. The result was a resolution of starting frame addresses finer
than the size of a single frame, and multiple frame-offset combinations that mapped to the same physical
hardware address. )
 Consider the following micro example, in which a process has 16 bytes of logical memory, mapped
in 4 byte pages into 32 bytes of physical memory. ( Presumably some other processes would be consuming
the remaining 16 bytes of physical memory. )

Figure 4.12 - Paging example for a 32-byte memory with 4-byte pages

 Note that paging is like having a table of relocation registers, one for each page of the logical
memory.
 There is no external fragmentation with paging. All blocks of physical memory are used, and there
are no gaps in between and no problems with finding the right sized hole for a particular chunk of
memory.
 There is, however, internal fragmentation. Memory is allocated in chunks the size of a page, and on
the average, the last page will only be half full, wasting on the average half a page of memory per process.
( Possibly more, if processes keep their code and data in separate pages. )
 Larger page sizes waste more memory, but are more efficient in terms of overhead. Modern trends
have been to increase page sizes, and some systems even have multiple size pages to try and make the best
of both worlds.
 Page table entries ( frame numbers ) are typically 32 bit numbers, allowing access to 2^32 physical
page frames. If those frames are 4 KB in size each, that translates to 16 TB of addressable physical
memory. ( 32 + 12 = 44 bits of physical address space. )
 When a process requests memory ( e.g. when its code is loaded in from disk ), free frames are
allocated from a free-frame list, and inserted into that process's page table.
 Processes are blocked from accessing anyone else's memory because all of their memory requests
are mapped through their page table. There is no way for them to generate an address that maps into any
other process's memory space.
98
 The operating system must keep track of each individual process's page table, updating it whenever
the process's pages get moved in and out of memory, and applying the correct page table when processing
system calls for a particular process. This all increases the overhead involved when swapping processes in
and out of the CPU. ( The currently active page table must be updated to reflect the process that is
currently running. )

Figure 4.13 - Free frames (a) before allocation and (b) after allocation

Hardware Support

 Page lookups must be done for every memory reference, and whenever a process gets swapped in or
out of the CPU, its page table must be swapped in and out too, along with the instruction registers, etc. It is
therefore appropriate to provide hardware support for this operation, in order to make it as fast as possible
and to make process switches as fast as possible also.
 One option is to use a set of registers for the page table. For example, the DEC PDP-11 uses 16-bit
addressing and 8 KB pages, resulting in only 8 pages per process. ( It takes 13 bits to address 8 KB of
offset, leaving only 3 bits to define a page number. )
 An alternate option is to store the page table in main memory, and to use a single register ( called the
page-table base register, PTBR ) to record where in memory the page table is located.
o Process switching is fast, because only the single register needs to be changed.
o However memory access just got half as fast, because every memory access now requires two
memory accesses - One to fetch the frame number from memory and then another one to access the desired
memory location.
o The solution to this problem is to use a very special high-speed memory device called the translation
look-aside buffer, TLB.
 The benefit of the TLB is that it can search an entire table for a key value in parallel, and if it
is found anywhere in the table, then the corresponding lookup value is returned.

99
Figure 4.14 - Paging hardware with TLB

The TLB is very expensive, however, and therefore very small. ( Not large enough to hold the entire page
table. ) It is therefore used as a cache device.
Addresses are first checked against the TLB, and if the info is not there ( a TLB miss ), then the frame is
looked up from main memory and the TLB is updated.
If the TLB is full, then replacement strategies range from least-recently used, LRU to random.
Some TLBs allow some entries to be wired down, which means that they cannot be removed from the
TLB. Typically these would be kernel frames.
Some TLBs store address-space identifiers, ASIDs, to keep track of which process "owns" a particular
entry in the TLB. This allows entries from multiple processes to be stored simultaneously in the TLB
without granting one process access to some other process's memory location. Without this feature the
TLB has to be flushed clean with every process switch.
The percentage of time that the desired information is found in the TLB is termed the hit ratio.
( Eighth Edition Version: ) For example, suppose that it takes 100 nanoseconds to access main memory,
and only 20 nanoseconds to search the TLB. So a TLB hit takes 120 nanoseconds total ( 20 to find the
frame number and then another 100 to go get the data ), and a TLB miss takes 220 ( 20 to search the TLB,
100 to go get the frame number, and then another 100 to go get the data. ) So with an 80% TLB hit ratio,
the average memory access time would be:
0.80 * 120 + 0.20 * 220 = 140 nanoseconds
for a 40% slowdown to get the frame number. A 98% hit rate would yield 122 nanoseconds average
access time ( you should verify this ), for a 22% slowdown.
( Ninth Edition Version: ) The ninth edition ignores the 20 nanoseconds required to search the TLB,
yielding
0.80 * 100 + 0.20 * 200 = 120 nanoseconds
for a 20% slowdown to get the frame number. A 99% hit rate would yield 101 nanoseconds average
access time ( you should verify this ), for a 1% slowdown.
Protection
The page table can also help to protect processes from accessing memory that they shouldn't, or their own
memory in ways that they shouldn't.
A bit or bits can be added to the page table to classify a page as read-write, read-only, read-write-execute,
or some combination of these sorts of things. Then each memory reference can be checked to ensure it is
accessing the memory in the appropriate mode.
Valid / invalid bits can be added to "mask off" entries in the page table that are not in use by the current
process, as shown by example in Figure 3.12 below.
Note that the valid / invalid bits described above cannot block all illegal memory accesses, due to the
100
internal fragmentation. ( Areas of memory in the last page that are not entirely filled by the process, and
may contain data left over by whoever used that frame last. )
Many processes do not use all of the page table available to them, particularly in modern systems with very
large potential page tables. Rather than waste memory by creating a full-size page table for every process,
some systems use a page-table length register, PTLR, to specify the length of the page table.

Figure 4.15 - Valid (v) or invalid (i) bit in page table

Shared Pages

 Paging systems can make it very easy to share blocks of memory, by simply duplicating page
numbers in multiple page frames. This may be done with either code or data.
 If code is reentrant, that means that it does not write to or change the code in any way ( it is non self-
modifying ), and it is therefore safe to re-enter it. More importantly, it means the code can be shared by
multiple processes, so long as each has their own copy of the data and registers, including the instruction
register.
 In the example given below, three different users are running the editor simultaneously, but the code
is only loaded into memory ( in the page frames ) one time.
 Some systems also implement shared memory in this fashion.

101
Figure 4.16 - Sharing of code in a paging environment

Structure of the Page Table

Hierarchical Paging

 Most modern computer systems support logical address spaces of 2^32 to 2^64.
 With a 2^32 address space and 4K ( 2^12 ) page sizes, this leave 2^20 entries in the page table. At 4
bytes per entry, this amounts to a 4 MB page table, which is too large to reasonably keep in contiguous
memory. ( And to swap in and out of memory with each process switch. ) Note that with 4K pages, this
would take 1024 pages just to hold the page table!
 One option is to use a two-tier paging system, i.e. to page the page table.
 For example, the 20 bits described above could be broken down into two 10-bit page numbers. The
first identifies an entry in the outer page table, which identifies where in memory to find one page of an
inner page table. The second 10 bits finds a specific entry in that inner page table, which in turn identifies a
particular frame in physical memory. ( The remaining 12 bits of the 32 bit logical address are the offset
within the 4K frame. )

102
Figure 4.17 A two-level page-table scheme

Figure 4.18 - Address translation for a two-level 32-bit paging architecture

 VAX Architecture divides 32-bit addresses into 4 equal sized sections, and each page is 512 bytes,
yielding an address form of:

 With a 64-bit logical address space and 4K pages, there are 52 bits worth of page numbers, which is
still too many even for two-level paging. One could increase the paging level, but with 10-bit page tables it
would take 7 levels of indirection, which would be prohibitively slow memory access. So some other
approach must be used.

64-bits Two-tiered leaves 42 bits in outer table

Going to a fourth level still leaves 32 bits in the outer table.

103
Hashed Page Tables

 One common data structure for accessing data that is sparsely distributed over a broad range of
possible values is with hash tables. Figure 3.16 below illustrates a hashed page table using chain-and-
bucket hashing:

Figure 3.19 - Hashed page table

Inverted Page Tables

 Another approach is to use an inverted page table. Instead of a table listing all of the pages for a
particular process, an inverted page table lists all of the pages currently loaded in memory, for all
processes. ( I.e. there is one entry per frame instead of one entry per page. )
 Access to an inverted page table can be slow, as it may be necessary to search the entire table in order
to find the desired page ( or to discover that it is not there. ) Hashing the table can help speedup the search
process.
 Inverted page tables prohibit the normal method of implementing shared memory, which is to map
multiple logical pages to a common physical frame. ( Because each frame is now mapped to one and only
one process. )

Figure 4.20 - Inverted page table

104
4.7.1.1 IA-32 Segmentation

 The Pentium CPU provides both pure segmentation and segmentation with paging. In the latter case,
the CPU generates a logical address ( segment-offset pair ), which the segmentation unit converts into a
logical linear address, which in turn is mapped to a physical frame by the paging unit, as shown in Figure
3.21:

Figure 4.21 - Logical to physical address translation in IA-32

IA-32 Segmentation

 The Pentium architecture allows segments to be as large as 4 GB, ( 24 bits of offset ).


 Processes can have as many as 16K segments, divided into two 8K groups:
o 8K private to that particular process, stored in the Local Descriptor Table, LDT.
o 8K shared among all processes, stored in the Global Descriptor Table, GDT.
 Logical addresses are ( selector, offset ) pairs, where the selector is made up of 16 bits:
o A 13 bit segment number ( up to 8K )
o A 1 bit flag for LDT vs. GDT.
o 2 bits for protection codes.

o The descriptor tables contain 8-byte descriptions of each segment, including base and limit registers.
o Logical linear addresses are generated by looking the selector up in the descriptor table and adding
the appropriate base address to the offset, as shown in Figure 3.22:

Figure 4.22 - IA-32 segmentation

105
IA-32 Paging

 Pentium paging normally uses a two-tier paging scheme, with the first 10 bits being a page number
for an outer page table ( a.k.a. page directory ), and the next 10 bits being a page number within one of the
1024 inner page tables, leaving the remaining 12 bits as an offset into a 4K page.

 A special bit in the page directory can indicate that this page is a 4MB page, in which case the
remaining 22 bits are all used as offset and the inner tier of page tables is not used.
 The CR3 register points to the page directory for the current process, as shown in Figure 8.23 below.
 If the inner page table is currently swapped out to disk, then the page directory will have an "invalid
bit" set, and the remaining 31 bits provide information on where to find the swapped out page table on the
disk.

Figure 4.23 - Paging in the IA-32 architecture.

106
Figure 4.24 - Page address extensions.

VIRTUAL MEMORY

 In practice, most real processes do not need all their pages, or at least not all at once, for several
reasons:
1. Error handling code is not needed unless that specific error occurs, some of which are quite rare.
2. Arrays are often over-sized for worst-case scenarios, and only a small fraction of the arrays are
actually used in practice.
3. Certain features of certain programs are rarely used, such as the routine to balance the federal budget.
:-)
 The ability to load only the portions of processes that were actually needed ( and only when they were
needed ) has several benefits:
o Programs could be written for a much larger address space ( virtual memory space ) than physically
exists on the computer.
o Because each process is only using a fraction of their total address space, there is more memory left
for other programs, improving CPU utilization and system throughput.
o Less I/O is needed for swapping processes in and out of RAM, speeding things up.
Figure below shows the general layout of virtual memory, which can be much larger than physical
memory:

107
Figure 4.25 - Diagram showing virtual memory that is larger than physical memory

 Figure 4.25 shows virtual address space, which is the programmers logical view of process memory
storage. The actual physical layout is controlled by the process's page table.
 Note that the address space shown in Figure 9.2 is sparse - A great hole in the middle of the address
space is never used, unless the stack and/or the heap grow to fill the hole.

Figure 4.26 - Virtual address space

 Virtual memory also allows the sharing of files and memory by multiple processes, with several benefits:
o System libraries can be shared by mapping them into the virtual address space of more than one process.
o Processes can also share virtual memory by mapping the same block of memory to more than one process.
o Process pages can be shared during a fork( ) system call, eliminating the need to copy all of the pages of the
original ( parent ) process.

108
Figure 4.27 - Shared library using virtual memory

Demand Paging

 The basic idea behind demand paging is that when a process is swapped in, its pages are not swapped in all
at once. Rather they are swapped in only when the process needs them. ( on demand. ) This is termed a lazy
swapper, although a pager is a more accurate term.

Figure 4.28 - Transfer of a paged memory to contiguous disk space

Basic Concepts

 The basic idea behind paging is that when a process is swapped in, the pager only loads into memory those
pages that it expects the process to need ( right away. )

109
 Pages that are not loaded into memory are marked as invalid in the page table, using the invalid bit. ( The
rest of the page table entry may either be blank or contain information about where to find the swapped-out
page on the hard drive. )
 If the process only ever accesses pages that are loaded in memory ( memory resident pages ), then the
process runs exactly as if all the pages were loaded in to memory.

Figure 4.29 - Page table when some pages are not in main memory.

 On the other hand, if a page is needed that was not originally loaded up, then a page fault trap is generated,
which must be handled in a series of steps:
1.The memory address requested is first checked, to make sure it was a valid memory request.
2.If the reference was invalid, the process is terminated. Otherwise, the page must be paged in.
3.A free frame is located, possibly from a free-frame list.
4.A disk operation is scheduled to bring in the necessary page from disk. ( This will usually block the process
on an I/O wait, allowing some other process to use the CPU in the meantime. )
5. When the I/O operation is complete, the process's page table is updated with the new frame number, and
the invalid bit is changed to indicate that this is now a valid page reference.
6. The instruction that caused the page fault must now be restarted from the beginning, ( as soon as this
process gets another turn on the CPU. )

Figure 4.30 - Steps in handling a page fault

 In an extreme case, NO pages are swapped in for a process until they are requested by page faults.
This is known as pure demand paging.

110
 In theory each instruction could generate multiple page faults. In practice this is very rare, due to
locality of reference, covered in section 9.6.1.
 The hardware necessary to support virtual memory is the same as for paging and swapping: A page
table and secondary memory. ( Swap space, whose allocation is discussed in chapter 12. )
 A crucial part of the process is that the instruction must be restarted from scratch once the desired
page has been made available in memory. For most simple instructions this is not a major difficulty.
However there are some architectures that allow a single instruction to modify a fairly large block of data,
( which may span a page boundary ), and if some of the data gets modified before the page fault occurs,
this could cause problems. One solution is to access both ends of the block before executing the instruction,
guaranteeing that the necessary pages get paged in before the instruction begins.

Performance of Demand Paging

 Obviously there is some slowdown and performance hit whenever a page fault occurs and the system has to
go get it from memory, but just how big a hit is it exactly?
 There are many steps that occur when servicing a page fault ( see book for full details ), and some of the
steps are optional or variable. But just for the sake of discussion, suppose that a normal memory access
requires 200 nanoseconds, and that servicing a page fault takes 8 milliseconds. ( 8,000,000 nanoseconds, or
40,000 times a normal memory access. ) With a page fault rate of p, ( on a scale from 0 to 1 ), the effective
access time is now:

( 1 - p ) * ( 200 ) + p * 8000000 = 200 + 7,999,800 * p

which clearly depends heavily on p! Even if only one access in 1000 causes a page fault, the
effective access time drops from 200 nanoseconds to 8.2 microseconds, a slowdown of a factor of 40
times. In order to keep the slowdown less than 10%, the page fault rate must be less than 0.0000025,
or one in 399,990 accesses.

 A subtlety is that swap space is faster to access than the regular file system, because it does not have to go
through the whole directory structure. For this reason some systems will transfer an entire process from the
file system to swap space before starting up the process, so that future paging all occurs from the
( relatively ) faster swap space.
 Some systems use demand paging directly from the file system for binary code ( which never changes and
hence does not have to be stored on a page operation ), and to reserve the swap space for data segments that
must be stored. This approach is used by both Solaris and BSD Unix.

Page Replacement

 In order to make the most use of virtual memory, we load several processes into memory at the same time.
Since we only load the pages that are actually needed by each process at any given time, there is room to
load many more processes than if we had to load in the entire process.
 However memory is also needed for other purposes ( such as I/O buffering ), and what happens if some
process suddenly decides it needs more pages and there aren't any free frames available? There are several
possible solutions to consider:
1. Adjust the memory used by I/O buffering, etc., to free up some frames for user processes. The decision of
how to allocate memory for I/O versus user processes is a complex one, yielding different policies on
different systems. ( Some allocate a fixed amount for I/O, and others let the I/O system contend for
memory along with everything else. )
2. Put the process requesting more pages into a wait queue until some free frames become available.
111
3. Swap some process out of memory completely, freeing up its page frames.
4. Find some page in memory that isn't being used right now, and swap that page only out to disk, freeing up
a frame that can be allocated to the process requesting it. This is known as page replacement, and is the
most common solution. There are many different algorithms for page replacement, which is the subject of
the remainder of this section.

Figure 4.31 - Need for page replacement.

Basic Page Replacement

 The previously discussed page-fault processing assumed that there would be free frames available on the
free-frame list. Now the page-fault handling must be modified to free up a frame if necessary, as follows:
1. Find the location of the desired page on the disk, either in swap space or in the file system.
2.Find a free frame:
a. If there is a free frame, use it.
b. If there is no free frame, use a page-replacement algorithm to select an existing frame to be replaced,
known as the victim frame.
c.Write the victim frame to disk. Change all related page tables to indicate that this page is no longer in
memory.
3. Read in the desired page and store it in the frame. Adjust all related page and frame tables to indicate the
change.
4. Restart the process that was waiting for this page.

Figure 4.32 - Page replacement.


112
 Note that step 3c adds an extra disk write to the page-fault handling, effectively doubling the time
required to process a page fault. This can be alleviated somewhat by assigning a modify bit, or dirty bit to
each page, indicating whether or not it has been changed since it was last loaded in from disk. If the dirty
bit has not been set, then the page is unchanged, and does not need to be written out to disk. Otherwise the
page write is required. It should come as no surprise that many page replacement strategies specifically
look for pages that do not have their dirty bit set, and preferentially select clean pages as victim pages. It
should also be obvious that unmodifiable code pages never get their dirty bits set.
 There are two major requirements to implement a successful demand paging system. We must
develop a frame-allocation algorithm and a page-replacement algorithm. The former centers around how
many frames are allocated to each process ( and to other needs ), and the latter deals with how to select a
page for replacement when there are no free frames available.
 The overall goal in selecting and tuning these algorithms is to generate the fewest number of overall
page faults. Because disk access is so slow relative to memory access, even slight improvements to these
algorithms can yield large improvements in overall system performance.
 Algorithms are evaluated using a given string of memory accesses known as a reference string,
which can be generated in one of ( at least ) three common ways:
1. Randomly generated, either evenly distributed or with some distribution curve based on observed
system behavior. This is the fastest and easiest approach, but may not reflect real performance well, as it
ignores locality of reference.
2. Specifically designed sequences. These are useful for illustrating the properties of comparative
algorithms in published papers and textbooks, ( and also for homework and exam problems. :-) )
3. Recorded memory references from a live system. This may be the best approach, but the amount of
data collected can be enormous, on the order of a million addresses per second. The volume of collected
data can be reduced by making two important observations:
1. Only the page number that was accessed is relevant. The offset within that page does not
affect paging operations.
2. Successive accesses within the same page can be treated as a single page request, because all
requests after the first are guaranteed to be page hits. ( Since there are no intervening requests for other
pages that could remove this page from the page table. )
 So for example, if pages were of size 100 bytes, then the sequence of address requests ( 0100,
0432, 0101, 0612, 0634, 0688, 0132, 0038, 0420 ) would reduce to page requests ( 1, 4, 1, 6, 1, 0, 4 )
As the number of available frames increases, the number of page faults should decrease, as shown in Figure
3.33:

Figure 4.33 - Graph of page faults versus number of frames.


113
FIFO Page Replacement

 A simple and obvious page replacement strategy is FIFO, i.e. first-in-first-out.


 As new pages are brought in, they are added to the tail of a queue, and the page at the head of the queue is
the next victim. In the following example, 20 page requests result in 15 page faults:

Figure 4 .34 - FIFO page-replacement algorithm.

 Although FIFO is simple and easy, it is not always optimal, or even efficient.
 An interesting effect that can occur with FIFO is Belady's anomaly, in which increasing the number of
frames available can actually increase the number of page faults that occur! Consider, for example, the
following chart based on the page sequence ( 1, 2, 3, 4, 1, 2, 5, 1, 2, 3, 4, 5 ) and a varying number of
available frames. Obviously the maximum number of faults is 12 ( every request generates a fault ), and the
minimum number is 5 ( each page loaded only once ), but in between there are some interesting results:

Figure 4.35 - Page-fault curve for FIFO replacement on a reference string.

Optimal Page Replacement

 The discovery of Belady's anomaly lead to the search for an optimal page-replacement algorithm, which is
simply that which yields the lowest of all possible page-faults, and which does not suffer from Belady's
anomaly.
 Such an algorithm does exist, and is called OPT orMIN. This algorithm is simply "Replace the page that
will not be used for the longest time in the future."

114
 For example, Figure 9.14 shows that by applying OPT to the same reference string used for the FIFO
example, the minimum number of possible page faults is 9. Since 6 of the page-faults are unavoidable ( the
first reference to each new page ), FIFO can be shown to require 3 times as many ( extra ) page faults as the
optimal algorithm. ( Note: The book claims that only the first three page faults are required by all
algorithms, indicating that FIFO is only twice as bad as OPT. )
 Unfortunately OPT cannot be implemented in practice, because it requires foretelling the future, but it
makes a nice benchmark for the comparison and evaluation of real proposed new algorithms.
 In practice most page-replacement algorithms try to approximate OPT by predicting ( estimating ) in one
fashion or another what page will not be used for the longest period of time. The basis of FIFO is the
prediction that the page that was brought in the longest time ago is the one that will not be needed again for
the longest future time, but as we shall see, there are many other prediction methods, all striving to match
the performance of OPT.

Figure 4.36 - Optimal page-replacement algorithm

LRU Page Replacement

 The prediction behind LRU, the Least Recently Used, algorithm is that the page that has not been used in
the longest time is the one that will not be used again in the near future. ( Note the distinction between
FIFO and LRU: The former looks at the oldest load time, and the latter looks at the oldest use time. )
 Some view LRU as analogous to OPT, except looking backwards in time instead of forwards. ( OPT has
the interesting property that for any reference string S and its reverse R, OPT will generate the same
number of page faults for S and for R. It turns out that LRU has this same property. )
 Figure 9.15 illustrates LRU for our sample string, yielding 12 page faults, ( as compared to 15 for FIFO
and 9 for OPT. )

Figure 4.37 - LRU page-replacement algorithm.

 LRU is considered a good replacement policy, and is often used. The problem is how exactly to implement
it. There are two simple approaches commonly used:
115
1. Counters. Every memory access increments a counter, and the current value of this counter is stored in the
page table entry for that page. Then finding the LRU page involves simple searching the table for the page
with the smallest counter value. Note that overflowing of the counter must be considered.
2. Stack. Another approach is to use a stack, and whenever a page is accessed, pull that page from the middle
of the stack and place it on the top. The LRU page will always be at the bottom of the stack. Because this
requires removing objects from the middle of the stack, a doubly linked list is the recommended data
structure.
 Note that both implementations of LRU require hardware support, either for incrementing the counter or
for managing the stack, as these operations must be performed for every memory access.
 Neither LRU or OPT exhibit Belady's anomaly. Both belong to a class of page-replacement algorithms
called stack algorithms, which can never exhibit Belady's anomaly. A stack algorithm is one in which the
pages kept in memory for a frame set of size N will always be a subset of the pages kept for a frame size of
N + 1. In the case of LRU, ( and particularly the stack implementation thereof ), the top N pages of the
stack will be the same for all frame set sizes of N or anything larger.

Figure 4.38 - Use of a stack to record the most recent page references.

LRU-Approximation Page Replacement

 Unfortunately full implementation of LRU requires hardware support, and few systems provide the full
hardware support necessary.
 However many systems offer some degree of HW support, enough to approximate LRU fairly well. ( In the
absence of ANY hardware support, FIFO might be the best available choice. )
 In particular, many systems provide a reference bit for every entry in a page table, which is set anytime
that page is accessed. Initially all bits are set to zero, and they can also all be cleared at any time. One bit of
precision is enough to distinguish pages that have been accessed since the last clear from those that have
not, but does not provide any finer grain of detail.

Additional-Reference-Bits Algorithm

 Finer grain is possible by storing the most recent 8 reference bits for each page in an 8-bit byte in the page
table entry, which is interpreted as an unsigned int.
o At periodic intervals ( clock interrupts ), the OS takes over, and right-shifts each of the reference bytes by
one bit.
o The high-order ( leftmost ) bit is then filled in with the current value of the reference bit, and the reference
bits are cleared.
o At any given time, the page with the smallest value for the reference byte is the LRU page.
 Obviously the specific number of bits used and the frequency with which the reference byte is updated are
adjustable, and are tuned to give the fastest performance on a given hardware platform.
116
Second-Chance Algorithm

 The second chance algorithm is essentially a FIFO, except the reference bit is used to give pages a second
chance at staying in the page table.
o When a page must be replaced, the page table is scanned in a FIFO ( circular queue ) manner.
o If a page is found with its reference bit not set, then that page is selected as the next victim.
o If, however, the next page in the FIFO does have its reference bit set, then it is given a second chance:
 The reference bit is cleared, and the FIFO search continues.
 If some other page is found that did not have its reference bit set, then that page will be selected as the
victim, and this page ( the one being given the second chance ) will be allowed to stay in the page table.
 If , however, there are no other pages that do not have their reference bit set, then this page will be selected
as the victim when the FIFO search circles back around to this page on the second pass.
 If all reference bits in the table are set, then second chance degrades to FIFO, but also requires a complete
search of the table for every page-replacement.
 As long as there are some pages whose reference bits are not set, then any page referenced frequently
enough gets to stay in the page table indefinitely.
 This algorithm is also known as the clock algorithm, from the hands of the clock moving around the
circular queue.

Figure 4.39 - Second-chance ( clock ) page-replacement algorithm.

Enhanced Second-Chance Algorithm

 The enhanced second chance algorithm looks at the reference bit and the modify bit ( dirty bit ) as an
ordered page, and classifies pages into one of four classes:
1.( 0, 0 ) - Neither recently used nor modified.
2.( 0, 1 ) - Not recently used, but modified.
3.( 1, 0 ) - Recently used, but clean.
4.( 1, 1 ) - Recently used and modified.
 This algorithm searches the page table in a circular fashion ( in as many as four passes ), looking for the
first page it can find in the lowest numbered category. I.e. it first makes a pass looking for a ( 0, 0 ), and
then if it can't find one, it makes another pass looking for a ( 0, 1 ), etc.
 The main difference between this algorithm and the previous one is the preference for replacing clean
pages if possible.

117
Counting-Based Page Replacement

 There are several algorithms based on counting the number of references that have been made to a given
page, such as:
o Least Frequently Used, LFU: Replace the page with the lowest reference count. A problem can occur if a
page is used frequently initially and then not used any more, as the reference count remains high. A
solution to this problem is to right-shift the counters periodically, yielding a time-decaying average
reference count.
o Most Frequently Used, MFU: Replace the page with the highest reference count. The logic behind this
idea is that pages that have already been referenced a lot have been in the system a long time, and we are
probably done with them, whereas pages referenced only a few times have only recently been loaded, and
we still need them.
 In general counting-based algorithms are not commonly used, as their implementation is expensive and
they do not approximate OPT well.

Page-Buffering Algorithms
There are a number of page-buffering algorithms that can be used in conjunction with the afore-
mentioned algorithms, to improve overall performance and sometimes make up for inherent weaknesses in
the hardware and/or the underlying page-replacement algorithms:

 Maintain a certain minimum number of free frames at all times. When a page-fault occurs, go ahead and
allocate one of the free frames from the free list first, to get the requesting process up and running again as
quickly as possible, and then select a victim page to write to disk and free up a frame as a second step.
 Keep a list of modified pages, and when the I/O system is otherwise idle, have it write these pages out to
disk, and then clear the modify bits, thereby increasing the chance of finding a "clean" page for the next
potential victim.
 Keep a pool of free frames, but remember what page was in it before it was made free. Since the data in the
page is not actually cleared out when the page is freed, it can be made an active page again without having
to load in any new data from disk. This is useful when an algorithm mistakenly replaces a page that in fact
is needed again soon.

Applications and Page Replacement

 Some applications ( most notably database programs ) understand their data accessing and caching needs
better than the general-purpose OS, and should therefore be given reign to do their own memory
management.
 Sometimes such programs are given a raw disk partition to work with, containing raw data blocks and no
file system structure. It is then up to the application to use this disk partition as extended memory or for
whatever other reasons it sees fit.

Allocation of Frames

We said earlier that there were two important tasks in virtual memory management: a page-replacement
strategy and a frame-allocation strategy. This section covers the second part of that pair.

118
Minimum Number of Frames

 The absolute minimum number of frames that a process must be allocated is dependent on system
architecture, and corresponds to the worst-case scenario of the number of pages that could be touched by a
single ( machine ) instruction.
 If an instruction ( and its operands ) spans a page boundary, then multiple pages could be needed just for
the instruction fetch.
 Memory references in an instruction touch more pages, and if those memory locations can span page
boundaries, then multiple pages could be needed for operand access also.
 The worst case involves indirect addressing, particularly where multiple levels of indirect addressing are
allowed. Left unchecked, a pointer to a pointer to a pointer to a pointer to a . . . could theoretically touch
every page in the virtual address space in a single machine instruction, requiring every virtual page be
loaded into physical memory simultaneously. For this reason architectures place a limit ( say 16 ) on the
number of levels of indirection allowed in an instruction, which is enforced with a counter initialized to the
limit and decremented with every level of indirection in an instruction - If the counter reaches zero, then an
"excessive indirection" trap occurs. This example would still require a minimum frame allocation of 17 per
process.

Allocation Algorithms

 Equal Allocation - If there are m frames available and n processes to share them, each process gets m / n
frames, and the leftovers are kept in a free-frame buffer pool.
 Proportional Allocation - Allocate the frames proportionally to the size of the process, relative to the total
size of all processes. So if the size of process i is S_i, and S is the sum of all S_i, then the allocation for
process P_i is a_i = m * S_i / S.
 Variations on proportional allocation could consider priority of process rather than just their size.
 Obviously all allocations fluctuate over time as the number of available free frames, m, fluctuates, and all
are also subject to the constraints of minimum allocation. ( If the minimum allocations cannot be met, then
processes must either be swapped out or not allowed to start until more free frames become available. )

Global versus Local Allocation

 One big question is whether frame allocation ( page replacement ) occurs on a local or global level.
 With local replacement, the number of pages allocated to a process is fixed, and page replacement occurs
only amongst the pages allocated to this process.
 With global replacement, any page may be a potential victim, whether it currently belongs to the process
seeking a free frame or not.
 Local page replacement allows processes to better control their own page fault rates, and leads to more
consistent performance of a given process over different system load levels.
 Global page replacement is overall more efficient, and is the more commonly used approach.

Non-Uniform Memory Access

 The above arguments all assume that all memory is equivalent, or at least has equivalent access times.
 This may not be the case in multiple-processor systems, especially where each CPU is physically located
on a separate circuit board which also holds some portion of the overall system memory.
 In these latter systems, CPUs can access memory that is physically located on the same board much faster
than the memory on the other boards.

119
 The basic solution is akin to processor affinity - At the same time that we try to schedule processes on the
same CPU to minimize cache misses, we also try to allocate memory for those processes on the same
boards, to minimize access times.
 The presence of threads complicates the picture, especially when the threads get loaded onto different
processors.
 Solaris uses an lgroup as a solution, in a hierarchical fashion based on relative latency. For example, all
processors and RAM on a single board would probably be in the same lgroup. Memory assignments are
made within the same lgroup if possible, or to the next nearest lgroup otherwise. ( Where "nearest" is
defined as having the lowest access time. )

Thrashing

 If a process cannot maintain its minimum required number of frames, then it must be swapped out, freeing
up frames for other processes. This is an intermediate level of CPU scheduling.
 But what about a process that can keep its minimum, but cannot keep all of the frames that it is currently
using on a regular basis? In this case it is forced to page out pages that it will need again in the very near
future, leading to large numbers of page faults.
 A process that is spending more time paging than executing is said to be thrashing.

Cause of Thrashing

 Early process scheduling schemes would control the level of multiprogramming allowed based on CPU
utilization, adding in more processes when CPU utilization was low.
 The problem is that when memory filled up and processes started spending lots of time waiting for their
pages to page in, then CPU utilization would lower, causing the schedule to add in even more processes
and exacerbating the problem! Eventually the system would essentially grind to a halt.
 Local page replacement policies can prevent one thrashing process from taking pages away from other
processes, but it still tends to clog up the I/O queue, thereby slowing down any other process that needs to
do even a little bit of paging ( or any other I/O for that matter. )

Figure 4.40 - Thrashing

 To prevent thrashing we must provide processes with as many frames as they really need "right now", but
how do we know what that is?

Working-Set Model

120
 The working set model is based on the concept of locality, and defines a working set window, of length
delta. Whatever pages are included in the most recent delta page references are said to be in the processes
working set window, and comprise its current working set, as illustrated in Figure 9.20:

Figure 4.41 - Working-set model.

 The selection of delta is critical to the success of the working set model - If it is too small then it does not
encompass all of the pages of the current locality, and if it is too large, then it encompasses pages that are
no longer being frequently accessed.
 The total demand, D, is the sum of the sizes of the working sets for all processes. If D exceeds the total
number of available frames, then at least one process is thrashing, because there are not enough frames
available to satisfy its minimum working set. If D is significantly less than the currently available frames,
then additional processes can be launched.
 The hard part of the working-set model is keeping track of what pages are in the current working set, since
every reference adds one to the set and removes one older page. An approximation can be made using
reference bits and a timer that goes off after a set interval of memory references:
o For example, suppose that we set the timer to go off after every 5000 references ( by any process ), and we
can store two additional historical reference bits in addition to the current reference bit.
o Every time the timer goes off, the current reference bit is copied to one of the two historical bits, and then
cleared.
o If any of the three bits is set, then that page was referenced within the last 15,000 references, and is
considered to be in that processes reference set.
o Finer resolution can be achieved with more historical bits and a more frequent timer, at the expense of
greater overhead.

Page-Fault Frequency

 A more direct approach is to recognize that what we really want to control is the page-fault rate, and to
allocate frames based on this directly measurable value. If the page-fault rate exceeds a certain upper bound
then that process needs more frames, and if it is below a given lower bound, then it can afford to give up
some of its frames to other processes.
 ( I suppose a page-replacement strategy could be devised that would select victim frames based on the
process with the lowest current page-fault frequency. )

121
Figure 4.42 - Page-fault frequency.

 Note that there is a direct relationship between the page-fault rate and the working-set, as a process moves
from one locality to another:

122

You might also like