ProgramsprogramprocessexecutablePIDinstance

Program versus Process

A program is a passive file of instructions on disk; a process is one running instance of it with its own address space, state and PID — which is why one chrome binary can be twenty processes and why killing one leaves the file untouched.

ConceptualLinux
▶ InteractiveInterview question
Progress

The problem

You have one file, /opt/google/chrome/chrome, and ps shows it running as PIDs 1201, 1229 and 1304, each using a different amount of memory, one of them at 90% CPU. If they are all "Chrome", what exactly is different between them, and what is shared?

A file is not a running thing

A program is bytes on storage: machine code, constants, a table of what to load where, and the names of the libraries it needs. It has no memory, no CPU time, no open files, no PID. You can copy it, sha256sum it, and delete it while a process built from it keeps running (on Unix-style systems the mapped pages stay valid because the kernel holds a reference to the inode, not the name — see Inodes).

A process is what the kernel creates when it runs a program: a private virtual address space, a set of registers (saved when it is not on a CPU), a scheduling state, an identity (PID, owner, parent), and a table of resources it holds — open files, sockets, locks, timers. The program is the recipe; the process is the meal. The recipe does not change when the meal burns.

The distinction sounds trivial until you debug. "The program uses too much memory" is meaningless; a specific process at a specific moment uses memory. "Restart the program" means create a new process from the same file, with fresh state and a new PID. "Update the binary" changes the file but not the processes already built from the old bytes — every process started before the deploy keeps running the old code until it exits.

One executable, three processes

Linux

Running the same executable three times produces three processes that share almost nothing they can observe. Each has its own address space: the global variable counter at virtual address 0x4c2010 in PID 1201 is a different physical byte from counter at the same virtual address in PID 1229. Each has its own descriptor table, so descriptor 5 is a different socket in each. Each has its own exit status, its own scheduling history, and can be killed independently.

What they do share is invisible to them: the kernel maps the same physical pages of machine code into all three, because code is read-only and identical. Twenty Chrome processes cost one copy of Chrome’s text in RAM, not twenty. The RSS column in ps counts those shared pages in every process, which is why summing RSS across processes over-estimates total memory use; PSS in /proc/<pid>/smaps divides shared pages by the number of sharers.

`ps` on a Linux desktop (values illustrative)
$ ps -o pid,ppid,stat,rss,pcpu,comm -C chrome
  PID  PPID STAT   RSS %CPU COMMAND
 1201  1180 Sl  312840  2.1 chrome     ← browser process
 1229  1201 Sl  189332  0.3 chrome     ← GPU process
 1304  1201 Rl  524116 89.7 chrome     ← a renderer, busy
 1305  1201 Sl   98120  0.0 chrome     ← another renderer, idle

What a process owns

The kernel keeps one record per process — traditionally called the process control block, task_struct in Linux — and everything the process "has" is reachable from it. The Anatomy of a Process walks the fields. For now, the shape is: identity (PID, parent PID, uid/gid), a pointer to the address space, saved CPU registers, scheduling state and priority, the descriptor table, pending signals, resource limits, and accounting (CPU time consumed, page faults taken).

Because the record is the process, "a process exists" means exactly "the kernel has such a record". The moment the record is freed the PID may be reused — which is why holding a PID across time and assuming it still names the same process is a classic bug (kill by stale PID hitting an unrelated process).

State, briefly

At any instant a process is doing one of a handful of things: it is on a CPU (running), it could be on a CPU but none is free (ready/runnable), it is waiting for something that has not happened yet (blocked: a disk read, a packet, a lock, a timer), or it has exited and is waiting for its parent to collect the exit status. The busy renderer above is R; the idle ones are S, sleeping in a poll() on their IPC pipe.

That state is what the scheduler reads, and it is what you read in top when something is wrong. Process States gives the full machine, including the Unix-specific zombie and stopped states and why "blocked" is where most processes spend most of their lives.

Key points

  • Program = passive bytes on disk. Process = a kernel record plus an address space, registers, state and resources built from those bytes.
  • Running the same program N times gives N processes with private data, private descriptors and private PIDs; only read-only code pages are physically shared.
  • Updating the binary does not change running processes; restarting means a new process with fresh state.
  • A process exists exactly as long as its kernel record; PIDs are reused after that.
  • Each process is always in one scheduling state — running, ready, blocked or exited.

Why does this exist?

Mechanisms are answers to constraints. Open each question before reading the answer.

Why separate the program from the process at all?

So that one file can be run many times concurrently, each run isolated from the others, and so that the file can be replaced while old instances finish.

Why share code pages between instances but not data pages?

Code is read-only and identical, so sharing is free and safe; data diverges immediately, so each process needs its own copy (created lazily via copy-on-write after fork).

One program, many processes

One program, many processes
The executable is a file. A process is that file running — with its own PID, state and private memory.
On disk
/opt/chrome/chrome
180 MB · ELF executable · r-x
.text (code)60.0 MB
.data (globals)12.0 MB
resources, symbols108 MB
A program is passive: no PID, no state, no memory. It is a recipe.
No process yet — press Launch (up to 4).
Processes
0
Shared physical (text)
0 B
Private physical (heap+data)
0 B
Program vs process. The same 60 MB of code is mapped into every instance but exists once in RAM — read-only pages are safe to share. Everything a process writes (globals, heap, stack) is private, so four instances cost 4× the writable memory and 1× the code. Each process has its own PID, its own state and its own descriptor table; killing one leaves the others untouched.
Simulated

How it fails

What the failure looks like from inside real software.

  • A deploy replaces the binary, but the old process keeps running old code for hours; the fix "is not live" until a restart.
  • Summing RSS across a fleet of worker processes reports more memory than the machine has, because shared code pages are counted once per process.
  • A supervisor stores a PID, the process dies, the PID is reused by something unrelated, and the supervisor later kills the wrong process.
  • Two instances of the same program both write to the same log file with their own buffered offsets and interleave garbage, because the file is shared but the buffers are per-process.