Suppose a backend service is installed at:
That file can sit on storage for weeks without consuming CPU time or accepting a single request. It is a program: a stored set of instructions and data.
Now suppose a service manager starts four copies of it. The operating system creates four separate processes. Each process runs the same program, but each has its own identity, execution state, memory, and set of resources.
This distinction is the foundation of process management:
A program describes what can be executed. A process represents one particular execution of it.
In operating-system discussions, a program is the passive representation of code that can be executed.
A native executable usually contains:
On Linux, a native program is commonly stored in an ELF executable. Windows commonly uses PE, while macOS commonly uses Mach-O.
A program does not have a process ID. It does not have register values, a runtime stack, open network connections, or a current instruction being executed. Those properties make sense only after the program is running.
The executable is also not the only possible representation of a program. A Python script, Java bytecode, and a shell script all contain instructions in forms consumed by an interpreter or runtime. The operating system directly runs the native interpreter or runtime process, which then executes the script or bytecode.
The important property is passivity. Whether the stored form is native machine code or code for a runtime, the program by itself is not an active execution.
A process is an operating-system abstraction for a program in execution.
It includes the loaded program, but it includes much more than program code. Conceptually, a process brings together:
These pieces let the operating system determine which instructions belong to this execution, which memory it may access, which files it has opened, which user it is acting as, and where execution should continue.
The process is therefore both an execution environment and a resource container. It gives the operating system one object through which it can isolate, observe, control, and eventually clean up a running program.
Strictly speaking, the CPU executes a thread within a process. A newly started, ordinary single-threaded process has one thread of execution. The common phrase “the process is running” is convenient shorthand for one of its threads executing instructions.
Starting a program does not transform the file on storage into a process. The file remains a file. The operating system creates a new runtime object and uses the program to initialize it.
The transformation looks like this:
A start request arrives for the program on storage. The operating system then creates a process, which means it:
Only after all of that do the program's instructions begin executing.
The process's runtime state immediately starts diverging from the stored program.
Variables change. Functions create stack frames. Dynamic memory is allocated. Files and sockets are opened. Register values change after almost every instruction. None of this ordinary runtime activity rewrites the executable's initial values on storage.
For example, suppose the program contains:
The executable stores the initial value 0. If a process handles 500 requests, its in-memory variable may become 500. Starting another process from the same executable gives that new process its own variable initialized to 0.
This separation is why two instances of the same service can handle different requests without their ordinary global variables overwriting each other.
The operating system may safely share physical copies of read-only program code between processes as an optimization. That does not turn the processes into one process. Each still has a distinct address space and runtime identity.
There is no one-to-one relationship between a program file and a process.
Consider the sleep program:
The shell starts the same program twice. The result is two processes.
The two processes can be stopped independently. If one terminates, the other continues to exist.
They can also start with different inputs:
Both processes execute the same program. Their environment variables differ, so they may load different configuration, connect to different services, and exhibit different runtime behavior.
This pattern is common in backend systems. A process manager may start several worker processes from one deployed artifact. The code is shared conceptually, but each worker has its own PID, memory, resource usage, failures, and logs.
Loading simulation...
The words application, program, and process are often used interchangeably in casual conversation, but they describe different boundaries.
An application is a user-facing or operational unit. It may consist of one process, or it may coordinate several.
A web browser, for example, may use separate processes for its main interface, page rendering, extensions, and other services. A database installation may include a server process plus separate command-line utilities and maintenance programs.
Conversely, one program can support many application instances. A server executable may be started once for a development environment and several times in production.
When diagnosing a system, “the application is running” is therefore often too vague. The useful questions are which processes exist, which programs they are executing, and which process owns the resource or failure being investigated.
An executable path identifies a stored program. A process ID, or PID, identifies a particular process known to the operating system.
Suppose two processes are executing /opt/catalog/bin/catalog-server:
| Property | Process A | Process B |
|---|---|---|
| Executable path | Same | Same |
| Program instructions | Same | Same |
| PID | Different | Different |
| Arguments | May differ | May differ |
| Environment | May differ | May differ |
| Runtime memory | Separate | Separate |
| Open resources | Separate unless deliberately inherited or shared | Separate unless deliberately inherited or shared |
The executable name alone is therefore not enough to identify a production problem.
A log line that says only catalog-server failed may leave several candidate processes. A line containing the PID makes it possible to correlate the event with process metrics, open connections, and operating-system logs from that particular execution.
PIDs are not permanent identities. A PID is valid for the lifetime of a process, and the operating system may reuse the number after that process is gone. The executable file, meanwhile, may remain installed across thousands of process lifetimes.
Calling a process a running instance can cause a subtle misunderstanding.
A process remains a process even when it is not currently executing on a CPU. It may be ready for CPU time, waiting for input, paused by a debugger, or temporarily unable to continue.
The phrase program in execution means that the program has an active execution context and managed lifetime. It does not mean that its instructions run continuously from creation until termination.
This matters on a busy server. Thousands of processes can exist even though the machine has only a few dozen CPU cores. Only a limited number of their threads can execute at the same instant, but every process still retains its identity and resources while it exists.
A program file can remain on storage indefinitely. A process has a beginning and an end.
At creation, the operating system establishes the process's identity and execution environment. During its lifetime, the process can consume CPU time, change its memory, and acquire or release resources. At termination, it stops executing and the operating system reclaims its runtime resources.
The program file remains on storage the whole time. Process A starts and terminates, Process B starts and runs longer before terminating, and Process C starts and terminates. Each has its own beginning and end, and none of those endings affect the file.
A process failure normally ends that particular execution, not the stored program. A supervisor can start a fresh process from the same program file.
The distinction also explains why changing a deployed executable does not modify the variables of an already-running process. Deployment changes the stored program used for future starts. Existing processes have their own live execution state and generally must be restarted before the new program version takes effect.
The program-process relationship is easiest to see with a native executable:
Here, catalog-server contains machine code that becomes the foundation of the new process's address space.
With a Python script, the command is different:
At the operating-system level, the native executable is python3. The resulting process loads and interprets worker.py. The script is the application program, while the Python interpreter supplies the native process that executes it.
Java follows the same broad pattern:
The operating system starts a JVM process. The JVM then loads the bytecode and data from catalog.jar.
This distinction is useful when inspecting processes. A process-listing tool may show python3 or java as the executable name even though the engineer thinks of the running application as worker.py or catalog.jar. The command-line arguments often reveal which script or archive that runtime process is executing.
The distinction can be observed with one program and two process instances.
Start two copies of sleep and save their PIDs:
Display both:
A typical result is:
The COMMAND values are the same, while the PID values differ. These are two processes created from the same program.
Linux exposes the executable associated with each process through /proc:
Both paths will commonly resolve to:
Stop the two process instances:
The PIDs disappear from the process list, but /usr/bin/sleep remains on storage and can create new processes in the future.
| Program | Process |
|---|---|
| Passive instructions and initial data | Active execution environment |
| Usually represented by an executable, script, or bytecode file | Represented by kernel-managed runtime state |
| Stored on persistent storage | Exists from creation until termination |
| Has no PID | Has a PID |
| Has no changing register or stack state | Has live execution state |
| Does not own open runtime resources | Can hold files, sockets, and other resources |
| Can be used to start many executions | Represents one particular execution |
| Can persist across many executions | Has a finite, operating-system-managed lifetime |
The shortest reliable test is to ask:
Am I referring to stored instructions, or to one live execution with an identity and runtime state?
Stored instructions describe a program. A live execution is a process.
A program is a passive, stored representation of instructions and initial data. A process is one active execution of a program, with its own PID, address space, execution state, runtime settings, and resource references.
One program can be used to start many independent processes, and one application may consist of several programs and processes. A process can exist even when it is not currently executing on a CPU, and its lifetime is separate from the lifetime of the program file.
The central mental model is:
A program is the executable plan; a process is one operating-system-managed instance carrying out that plan.
5 quizzes