Robert Gray & Siobhan Quinn ============================= CSE 451: Friday, May 02, 2005 ============================================================================================= KEY POINT ============================================================================================= Why do we virtualize memory? Well, for the same reason that we virtualize everything: We want to present it to the programmer in a way that is different than it actually is. We want to be able to add features that increase memory access speed, provide protection and optimize memory usage. At the same time, we want the user programs to be independent of these changes. The user program can interact with memory through a virtualization layer (an interface) while the actual memory system is improved behind the scenes. This helps the programmer's code portable! Coders don't have to rewrite the software every time the hardware changes. ============================================================================================= -------------------------------------------------------------------------------------------------- SEGMENTATION -------------------------------------------------------------------------------------------------- A) Zero-Partition Strategy: Virtual Memory is directly mapped to Physical memory (with no translation) All processes operated on the physical memory addresses. This would make it easy for one process to corrupt the memory of another process or even the operating system. A process can index any part of memory. ( or a method of protection must be added ) B) Fixed-Partition Strategy: Physical Address = Virtual Address + Base Address Here, the operating system's role is to initialize the base register, address space ID, etc. Each process gets a fixed size of memory (no more no less). Problems: Internal Fragmentation. Fixed size segments are allocated to processes. If a program needs less memory that the segment size, then there is the potential to waste a lot of memory that can't be assigned to other processes. The more we reveal or expose the architecture to the program, the more difficult it becomes to make progress in the development of new hardware. The industry is always fighting between two pressures: the need to create better architecture, and the consumer need for backward compatibility. The more dependent a piece of software is on the details of the architecture, the less freedom the architecture has to evolve. What about the operating system? Well, the operating system is one piece of software that is allowed to be hardware-dependent. Otherwise, it couldn't perform all of the services we need it to. Also, while there might be many software applications running on a system, there is only one operating system, so it is alright to expect to transform a small portion of it when moving from architecture to architecture. C) Variable-Partition Strategy: Physical Address determined by Base/Length Register Physical = (Virtual < Length) ? (Base + virtual) : EXCEPTION Problems: It's dynamic, which almost always means there are going to be problems. One solution (obviously) is to grow the segment when necessary. Another solution is to allocate more than is necessary at the beginning and thereby push the problems off the future. Often, this can be the best method, since the future may never actually happen. We can also move the segment. However, touching memory is not only slow and costly in the fact that during the move the CPU is performing no useful work, but it also may result in external fragmentation. Once again, this all comes down to the space/time tradeoff: The finer we make the operations on space (although it will increase our overhead) the finer our granularity of memory management will be. D) Segmentation Strategy: Virtual Address is a combination of a "Selector" and an "Offset" Selector Offset +----------+------+ | | | +----------+------+ | | | +----------+------+ | | | +----------+------+ | | | +----------+------+ The selector chooses the block of physical memory that should be addressed, and the offset indicates the byte within that block. Note that with Segmentation, if Program1 and Program2 share an entry in the segmentation table, they can share the memory at that location, without an address violation. These two processes now easily share the segment of memory with each other. Now we also understand a little better what fork() does - it can simply copy the segment table for particular sections of the process. Disadvantages: The details ( the address translation, the number of segments and the size of the segments) are exposed to the program. When details are exposed they are often taken advantage of by the programmer. If a program relies on the underlying implementation then the code is not portable, and is dependent on the underlying memory management system. External Fragmentation ( need for compaction ). Memory is broken into pieces. The total available memory exceeds a give memory request - but it is broken into segments. So there is not enough CONTINGUOUS memory to satisfy the request. (this can be fixed by compaction - where you rearrange the memory so that all the free memory is lumped together - but that is an expensive process.) -------------------------------------------------------------------------------------------------- PAGING -------------------------------------------------------------------------------------------------- Paging: Fewer, smaller memory divisions with a completely hidden translation function Virtual Frame Number Virtual Offset +-------------------------+----------------+ | | | +-------------------------+----------------+ * All of physical memory is partitioned into many, small, equally-sized sections. * Every process has a page table that converts the Virtual Frame Number (the address that the program sees) into a Frame Address (the actual address in physical memory). The Virtual Offset is the location of the desired memory within that frame. * The Page Table allows the operating system to create an arbitrary translation function between the virtual memory and the physical memory. Advantages * The physical address space needs not be continuous. We have no external fragmentation. ANY free frame can be allocated to a process that needs it. * Flexible in that a process's memory is no longer limited by the segment length. The amount of memory a process uses can be different and change - by requesting any number of page frames. ( Since the frames don't need to be contiguous - this it is much easier to find the amount of memory you need ) Memory can also be shared among processes by copying one process's page table into the page table of a second process. * It also provides more portability. The user sees its memory as one contiguous piece. But in reality it's separated into different frames scattered in physical memory. As discussed earlier, programs written for a defined memory system may have to be rewritten when that memory architecture changes. In this system, a program can move from one paging architecture to another paging architecture without worrying about how the memory management system is implemented. Disadvantages: * Though paging is much more flexible than segmentation, a process is still restricted by certain hardware limitations. 1) the number of pages the hardware provides and 2) the size of each page. (Therefore it is not COMPLETELY independent of the hardware a it's running on ) * Also, although it sounds like a great idea, arbitrary translation is hard. It is costly in terms of time because every instruction must be indirected first, and it is costly in space because those indirections must take place through something. Next Monday: More on paging, and how do we make the arbitrary transitions fast?