Virtual address space
When a modern CPU executes a program instruction to access memory, it accepts a virtual address. It uses hardware to interpret the virtual address as a physical address and then to access the physical memory. Accessing memory through virtual addresses has the following advantages:
A program can use a series of neighboring virtual addresses to access large, non-contiguous memory buffers in physical memory.
A program can use a series of virtual addresses to access memory buffers that are larger than the available physical memory. When the physical memory supply is small, the memory manager saves the physical memory page (typically 4 KB) to the disk file. The data or code page moves between the physical memory and the disk as needed.
Virtual addresses used by different processes are isolated from each other. The code in one process cannot change the physical memory that is being used by another process.
The virtual address range available for a process is called the virtual address space for the process. Each user-mode process has its own private virtual address space. For 32-bit processes, the virtual address space is typically 2 GB, ranging from 0x00000000 to 0x7FFFFFFF.
So what is User mode?
User mode and kernel mode
This is also the concept of CPU. The CPU has these two modes of operation, the protection level of the two methods is different. Depending on the type of code running on the CPU, the CPU switches between two modes. The application runs in user mode, and the core operating system components run in kernel mode. It can be understood that the kernel mode has higher permissions and can perform instructions that the user mode cannot execute, such as device I/O.
In the remote DOS era, both the system and the program are running in real CPU mode (user mode is CPU)
Each user-mode process has its own private virtual address space, but all code running in kernel mode shares a single virtual address space called system space . The virtual address space for the current user-mode process is called user space .
shared memory and mapping files
Introduction: Shared memory is defined as memory that is visible to more than one process, or memory that appears in the virtual address space of multiple processes. So what's the role of sharing? It's very useful! Imagine that there are two processes in Windows that use the same DLL, so simply load the code in that DLL into physical memory once, and then share this memory between all the processes that need to use the DLL, save a lot of memory, and save time for repeated loading!
Demonstrates a scenario in which memory is shared between two processes.
As a modern operating system, Windows needs to provide this mechanism. While the memory manager of Windows implements the shared memory mechanism called a memory area object, It is also known as a file mapping object in the Windows API.
The virtual address of a process can be mapped to a memory area object, and the memory area object can be in a different place: ① in memory, ② in a paging file, ③ in another file (apparently a file on disk). But the application accesses the contents of these files as if they were in memory. How is this implemented? The following are discussed separately. Before discussing this, let's look at another concept:
Status of the page: idle, reserved, assigned.
A page in the address space of a process can be idle (free), reserved (Reserved), or allocated (Committed).
- Idle good understanding, the virtual address space of a process is just a logical concept, so if you do not do any processing, all the pages in this address space are free.
- Preserves the address space, similar to a thread that retains a range of virtual addresses for future use. The reserved address space is inaccessible because it is not yet assigned.
- Assigned pages refer to pages that, when accessed, are eventually translated into a valid page in physical memory. The assigned page can be private, unshared, or mapped to a memory area. If the assigned page is private, the other process cannot access it. If the assigned page is mapped to a portion of a mapping file (called a view), the system will read its contents from disk to memory the first time the page is accessed.
Summary : Only assigned pages are accessible, and access to the page must be access to physical memory. So if the page is mapped to disk, the first time it is accessed, the system needs to read the contents of the disk into memory.
The application can reserve the address space first, and then allocate the pages in the address space (at the appropriate time). Of course, they can also hold and assign pages once in the same function call. The corresponding APIs are VirtualAlloc and VirtualAllocEx.
Using the "Preserve redistribution" method saves memory, delaying the submission of assigned pages until the pages are really needed, while at the same time ensuring that the pages of the virtual address space are contiguous. Keeping memory operations overhead is minimal, just updating some small internal data structures (virtual address descriptors). This approach is useful for applications that may require large chunks of contiguous virtual memory: You do not need to allocate pages for the entire region, but you can leave the address space first, and then assign the page later if needed. For the operating system, a typical example is the user-mode stack of threads. The default size of the line stacks is 1MB, but when the system creates the thread, it simply retains a 1MB stack address space and allocates only the initial page of the stack. The next page is marked as a Guardian page, but is not assigned. Its role is to capture references to the stack's assigned pages and extend this section.
-----------------------I'm a split line--------------------------
Go back to the topic just now. As you can see from the discussion above, the process accesses the page regardless of the memory area object, and eventually loads the content into memory. This answers why the application accesses the contents of these files as if they were in memory.
This file is called a memory-mapped file when the memory-area object is (exactly, maps to) a file on a disk. When the memory area object is mapped to an allocated memory, the memory area is called the memory area supported by the paging file (forgive me, this name is Pan), because in-memory pages tend to correspond to paging files, which are written to the paging file if necessary. At this point, it provides the functionality of the previously mentioned shared memory.
Create a memory area object by calling the CreateFileMapping function. The first parameter of this function requires the handle of a file to be passed. If you pass in Invalid_handle_value, you are creating a memory area that is supported by the paging file. Other processes can access the memory area object through the handle returned by the function or the name of the file-mapped object.
The memory area object can even reference files that are much larger than the process's address space. In order to access a very large memory area object, a process can map only the portion of the memory area object that it is interested in (called a view of that memory area) by calling the MapViewOfFile function.
File mapping has a wide range of uses. The application can use it to easily perform file I/O, because only the mapping file needs to appear in its address space (think of the usual ReadFile, WriteFile cumbersome calls). The system's image loader can map executable image files, DLLs, and device drivers into memory using file mappings.
Windows Memory Management