Original address: PJMike’s blog
preface
This article is still a reading note for the book Operating Systems: Three Easy Pieces, which mainly shares some contents of virtual memory.
Early system
In terms of memory, early machines didn’t offer much abstraction to the user. Basically, the machine’s physical memory looks like this:
Multiple programs and time sharing
Today’s machines are multi-programs in which multiple processes are ready to run at a given time, such as when one process is waiting for I/O, and the operating system switches these processes.
Rough machine sharing
Soon, people began to require more machine, the era of time-sharing system was born, and a method to realize time sharing, is a process to take up all the memory alone run a short period of time, then stop it, and put it all state information stored in the disk, loading status information of the other processes, then run a period of time, This is the implementation of some crude machine sharing.
The problem with this approach is that it’s too slow, and it’s too slow to save all of the process’s memory information to disk. Therefore, we still keep process information in memory during process switching (the current practice), which is faster and the operating system can implement time-sharing more efficiently.
Efficient time sharing
As shown in the figure below, each of the three processes (A, B, C) has A small amount of memory cut out of 512KB of physical memory for them. Assuming only one CPU, the operating system chooses to run one of the processes (such as A) while the other processes (B and C) wait in A queue to run.
As time sharing becomes popular, people have new requirements for the operating system, especially when multiple programs reside in physical memory at the same time, “protection” becomes an important issue, specifically how to protect the memory owned by a process from being read by other processes, of course, modification is not allowed.
Address space
The operating system provides an easy-to-use physical memory abstraction called the address space, which is the memory on the system as seen by a running program. The address space of a process contains all the memory states of the running program. For example, the program’s code must be in memory. When the program is running, the stack is used to hold the current function call information, allocate space to local variables, and pass parameters and function return values. Finally, the heap is used to manage dynamically allocated, user-managed memory.
Here is a simple example of an address space. Let’s assume that we have a very small address space (only 16KB). The program code is located at the top of the address space (in this case it starts at 0 and is loaded into the first 1KB of the address space). As shown in the figure:
Of course, such address space is an abstraction provided by the operating system to the running program. The program is not actually in memory with 0 ~ 16KB physical address, but loaded at any physical address.
How to Virtualize Memory
The question then arises, how can multiple processes be loaded into different addresses of memory, and how can an operating system construct a private and potentially large abstraction of address space for multiple running processes (all processes sharing memory) on a single physical memory?
Modern operating systems solve this problem by introducing virtual memory mechanisms, which provide programs with an abstraction of a large, sparse, private address space that holds all of the program’s instructions and data. With the help of specialized hardware, the operating system converts each virtual memory index into a physical address, and the physical memory obtains the required information according to the obtained physical address.
Three goals for virtualized memory
This article does not discuss the specific implementation mechanism of virtual memory, but mainly shares the design idea of virtual memory, namely the following three goals
Voice-over: Understanding these three goals will give you a better understanding of the virtual memory mechanism
transparent
A major goal of virtual memory is “transparency.” The operating system should implement virtual memory in such a way that running programs cannot see it. Therefore, the program should not be aware of the fact that memory is virtualized, but instead behaves as if it has its own private physical memory. Behind the scenes, the operating system (and hardware) does all the work, allowing different jobs to reuse memory to achieve this illusion.
The efficiency of
Another goal of virtual memory is “efficiency.” Operating systems should pursue virtualization as efficiently as possible, both in terms of time (that is, not making programs run slower) and space (that is, not requiring much extra memory to support virtualization). To achieve efficient virtualization, operating systems have to rely on hardware support, including TLB capabilities.
To protect the
The third goal is “protection”, or “isolation”. The operating system should ensure that processes are protected from other processes and that the operating system itself is protected from processes. When a process performs load, store, or instruction extraction, it should not in any way access or affect the memory contents of any other process or the operating system itself.
Thus, protection allows us to provide isolated features between processes, each of which should run in its own independent environment, protected from other faulty or malicious processes
The resources
- Operating Systems: Three Easy Pieces