In a typical modern operating system, a page frame of RAM can essentially be one of four things:
- Free. Unallocated. Available for use at any time.
- Used by the operating system for its own internal purposes. An OS has data structures, and they need to live somewhere. Page tables might also fall under this general heading.
- A page that represents part of a memory-mapped file. As well as files memory-mapped by user programs, the the text and read-only data of running programs are invariably the executable file memory-mapped. The other main example is buffer cache, where the OS keeps commonly-used data from secondary storage around if it looks like it might be needed.
- "Anonymous memory" (this is the Unix term), which essentially means memory allocated by user programs. The reason why it's called "anonymous memory" is that it's memory that doesn't have a "name", in the sense of a file on disk. Anonymous memory includes user heap-allocated memory, call stacks, and memory shared between processes.
We'll ignore the first two for the moment, because they probably aren't relevant to your question, and just look at the last two.
If the page frame of memory represents part of a file, then it needs to be kept in sync with the copy in secondary storage. If it is a read-only mapping (which is the case for program text), then this is trivial.
If the OS needs more free page frames, and it determines that some piece of read-only file mapping is a good candidate for ejection, it can just be removed from everyone's virtual memory mapping and then freed. If it's read-write, then it may need to be written first, if it's a dirty copy.
If the page frame is anonymous memory, then there is no "file" that it is a copy of. However, all modern operating systems have support for swap space, where secondary storage can be used to store anonymous memory in a place other than RAM.
Some older operating systems (e.g. 4.3BSD) did essentially the same thing with anonymous memory as it did with memory-mapped files. All allocated memory was a copy, or cache, of swap space. This meant that you needed at least as much secondary storage dedicated to swap as you had RAM. At some point in the late 80s to mid 90s, this tradeoff made a lot of sense.
Modern operating systems don't do this anymore, and can handle having less swap than RAM, including no swap at all. An operating system may still internally pretend that anonymous memory is kind of a memory-mapped page from a kind of pseudo-device called "swap", but the way its managed is different.
OK, so that's the perspective of RAM. Now let's talk about the perspective of virtual memory.
Virtual memory is typically organised as a bunch of segments. A segment is a contiguous collection of pages which represent a contiguous region of a virtual memory "object". Different operating systems have a different idea about what a virtual memory object can be, but this usually means either a file, or anonymous memory.
If a user program tries to access a page which is not part of a segment, then this is what Unix famously calls a segmentation violation.
If a user program tries to access a page which is part of a segment, then this is a valid operation. (Assuming that the access itself is valid; you can't write to a read-only segment, for example.)
However, within a segment, a page may or may not be "valid", in the sense that its entry in the CPU's page tables currently points to a page frame of RAM. When a user program tries to access it, this causes a page fault, which traps to the operating system so it can intervene.
In the case of anonymous memory, there are lots of reasons why a page might not be valid:
- When memory is allocated by a program, the OS sets up a segment of anonymous memory, but it does not have to be mapped to actual RAM yet, and this can be desirable for speed. It is sufficient that enough memory (whether RAM or swap) to satisfy the allocation exists. All modern operating systems let user programs control this.
- The page may be swapped out. In this case, the OS will suspend the thread and read it in.
- The page may be copy-on-write. A page might be shared in such a way that if you only ever read it, you can safely share that copy, but writing to it must force a private copy to be made. I'll give a common example in a moment.
- The OS might just want to do it for its own housekeeping purposes. See this previous answer for some examples of when this might occur.
NOTE What follows is an explanation of one of the more common uses of copy-on-write memory. This doesn't really answer your question, but I'm including it because you might find it helpful, but feel free to skip or skim.
The use is in program executables. I'm going to go into a bit of detail as to how executable files are understood by a modern virtual memory system to make this somewhat self-contained, but if you already know this part, skip down to "read-write data".
A modern executable file (e.g. ELF, PE/COFF) is typically arranged as a bunch of segments. A typical layout is the following segments in roughly this order:
- "Text", which is executable code. This segment should be mapped as read-only and executable.
- "Read only data", which is data that the user programs shouldn't modify. This typically includes data structures generated by the compiler for its own purposes (e.g. data structures to implement virtual calls, exception handling, static initialisation, etc), or truly read-only data such as static strings. This segment should be mapped as read-only and not executable.
- "Read-write data", which is data that is initialised but user programs can write to. This segment should be mapped as read-write, not executable, but also copy-on-write. Why copy-on-write? Because writing to that data should not modify the executable file that you're running!
- "BSS", is static data that should be initialised to zero bytes and therefore doesn't need to take up any space in the executable file itself. This should be mapped as anonymous zero-fill memory.
When you run a program, this is how the operating system sets up a new virtual address space: it maps the segments from the executable in whatever way the executable requests.
By the way, the term "BSS" deserves some explanation. It was a pseudo-operation implemented on a particular assembler for the IBM 704 at some point in the mid-1950s, and it stood for "block starting symbol". By a series of historical accidents, the term has stuck and lives on today. Peter van der Linden suggested that "Better Save Space" might be a more suitable mnemonic.