When a program is compiled into an executable file, the compiler converts the program's executable statements (e.g. printf("Hello, World!"); ) that are of a specific size into machine code, and also knows how much room to allocate for the global and static variables (from their data types), thus resulting in a fixed amount of storage for the compiled program.
When a program is executed (aka running) it is often referred to as a process (e.g. on a Linux system), and is allocated four areas of memory:
- Return address
- Function parameters (passed in arguments)
- Local variables
- Dynamic memory allocation
- Initialised global and static variables
- Uninitialised variables
- Executable statements in machine code
Upon program execution the OS provides a new VAS (Virtual Address Space) for each process, whereby each virtual address is mapped to physical memory by use of a structure known as a page table. This is an abstraction of physical memory and the process effectively considers the full amount of memory available to it (as logical addresses). On a 32bit OS, the process has a 4GB VAS (2^32).
In reality, many programs are running at the same time with the underlying OS taking care of memory management.
The following represents two processes virtual address spaces being mapped to physical memory:
This representation shows the a single program being run as two processes (e.g. two instances of a text editor), sharing the same code segment in physical memory but with their own data and stack segments: