Basic Memory Management Requirements/Principles/Mechanism in Operating System:
Any mechanism and policy associated with memory management should satisfy certain requirements. Different requirements are as follows:
When a translator (compiler, interpreter, or assembler) translates a source code program into object code, it has no idea where the code will be loaded when the program is run. In fact, it may occupy a different area of memory each time it is run.
A programs will possibly be swapped in and out of memory. They may occupy different physical address locations at different, times. The translator cannot assign absolute physical addresses to instructions and data values in programs. But once the program code and data are loaded, processor and operating system must be able to reference the actual physical addresses. Relocation is a process of converting logical address to physical address.
Program address space includes process control information (PCB), program code, data segment (global data), and stack/heap space. This information may or may not be stored in contiguous locations but it can be visualized as a linear sequence of addresses.
Operating System must protect the address space of one process from unauthorized access by other processes. No process should be allowed to access kernel code or space. When address space is stored contiguously, protection is relatively easy to achieve.
Protection must be provided by the hardware not the operating system. There is no way to tell in advance which addresses a program might reference as it runs. Dynamic calculation of array subscripts, pointers, etc. is only done at execution time.
Under certain circumstances, memory protection must be relaxed. In some situation, several processes are executing the same program such as an editor. The memory is used more efficiently if each process uses the same copy of the program code. This kind of sharing is almost always done automatically by the system software.
Processes that cooperate to solve a problem (for example, the producer-consumer problem) may want to access shared data structures. The processes that will participate in the sharing must declare shared memory segments explicitly. The operating system is responsible for protecting the shared memory from unauthorized access by other processes. It must also make sure that the sharing processes are restricted to the shared portion of each other's address space.
4. Program Translation and Address Spaces:
A process has a logical address space. It is a linear set of locations that encompass the program code, variables, stack, etc. As the program executes, all or part of the logical address space is mapped to a physical address space. Physical address space is a subset of primary memory. The address space is a product of the translation-linking-loading process.
Translators generate re-locatable object code modules from source code. The various modules are then joined together (linked) to form a single module called load module. It is then loaded to memory.
At some point in time, the addresses produced by the 'translator must be converted to physical addresses. This process is called address binding. Addresses can be bound at compile time (rarely), load time, or run time. The most common binding time in modern systems is run time.
Different types of addresses are as follows:
- Symbolic addresses (variable names and occasionally named instructions) are used in the source code. The translator converts them to logical addresses.
- Logical addresses are assigned independent of the physical locations. They may still require additional mapping operations to be bound to absolute addresses.
- Relative addresses are a kind of logical address. The address is expressed as an offset from the start address of the module. It is is usually established as zero. The translator assigns relative addresses.
- Physical addresses (absolute addresses) refer to the actual location at which a particular instruction or variable is loaded
5. Loading and Linking:
The loading is performed in the following ways:
1. Absolute Loading:
An absolute loader copies a load module into memory. It makes no adjustments to the logical addresses assigned by the translator. It assumes that the translator or the programmer assigned the correct absolute addresses. With this approach, a load module must always occupy the same set of memory locations. This approach is virtually never used.
2. Re-Locatable Loading:
In this loading, the re-locatable loader adds an offset to each logical address in the program as it copies a load module into memory. This type of loader requires the translator to generate relative addresses. It is also necessary for the program to be loaded into consecutive memory locations. The physical addresses are found by adding M to each relative address. M is the start address of the load module.
In this case, addresses are bound at load time. It is more flexible approach than compile time binding. The program can be loaded into a separate set of locations each time it runs.
3. Dynamic Loading (Dynamic Relocation):
Re-locatable loading does not support swapping. Once a process has been loaded and relocated, its addresses are absolute. A swapped-out process could only be swapped back to the memory locations it started in. This is too restrictive.
Dynamic loading or dynamic relocation defers the process of determining absolute addresses until the address is used. The loader places the load module into memory without adjusting relative addresses. A special register is loaded with the start address of the load module. Hardware automatically adds the register contents to a relative address each time the address is used.
In this case, address binding is at run-time. Relocation is done each time the address is used. It must be handled in hardware.
A linker joins several object modules into a single load module. Input to the linker is a set of object modules. Each module has been translated with relative addresses, relative to 0 as the start address of the module. References from one module to another (function calls, data references, etc.) are still symbolic:
The loader must generate a single contiguous module in which all the external references have been resolved. The term Linkage editor is applied to this type of linker.
A dynamic linker postpones some of the linkage functions until run time. Dynamic linking can be done at load-time or at run time. Load-time dynamic linking prepares a relocatable load module in normal way. It leaves some external references unresolved. These references are usually to system utilities or language libraries. At load time, system copies of the target modules can be linked. Utilities can be changed without forcing programmers to re-link existing load modules. A shared code can be linked to more than one program.
Run-time dynamic linking goes a step farther. Some modules will not be linked in until they are actually called.
Overlaying is a technique that is used to execute a process even if the memory is not enough. The programmer can define two or more overalys. These overlays can execute in the memory independently. The operating system can swap overalys and manage the memory.
The disadvantage of overlying is that it require extensive involvement of programmer. The programmer has to identify and define overlays efficiently. It is a very difficult task.