Level 4 · Chapter 4
Job objects
How Windows implements 'kill the whole tree,' resource caps, and app-isolation limits — as one more kernel object, not special-case code.
Processes & threads described a process as an isolated container. Sometimes you genuinely need several processes to be managed as a single unit anyway — shared resource limits, coordinated teardown — without breaking their individual isolation. That's what a job object provides.
A container for containers
A job object is, structurally, just another kernel object managed through the same Object Manager machinery as everything else — but what it contains is a set of processes, and what it enforces is shared policy across all of them:
- Resource limits — a maximum total memory commit across every process in the job, a CPU rate limit, a maximum number of active processes, and similar caps applied to the group as a whole rather than to any one process individually.
- UI restrictions — a job can prevent its member processes from doing things like reading the clipboard, switching desktops, or creating top-level windows at all, a real isolation mechanism predating (and, in different contexts, complementing) AppContainer.
- Teardown behavior — closing a job's last handle can be configured to terminate every process still inside it, all at once.
- Breakaway policy — whether a child process is allowed to escape job membership when it's created, or whether it's forced to inherit its parent's job regardless.
Why "kill the whole tree" needs a job object at all
It's tempting to assume Windows tracks a full process tree and lets you terminate a parent and all its descendants directly — it doesn't, not by default. Process parent/child relationships in Windows are recorded loosely (a "parent process ID" field that isn't even guaranteed to still point at a live process), and there's no built-in "kill this process and everything it spawned" operation based on that relationship alone. A job object is precisely the mechanism that makes reliable, guaranteed group-teardown possible: assign every spawned process to the job (which can be enforced automatically via breakaway policy, so nothing can opt out), and terminating the job terminates every member, regardless of how deep the spawn tree got.
A worked example: why closing a build console kills the whole compiler chain
Build tools and IDEs commonly launch their compiler and linker processes inside a job object specifically so that pressing Ctrl+C, or closing the console window, reliably tears down the entire toolchain — the top-level build process plus every compiler invocation, linker pass, and helper tool it may have spawned along the way — in one action. Without a job object, closing the console would only affect the top-level process directly; anything it spawned that had already detached (or whose parent simply exited before it) could be left running orphaned.
Job membership is not the same as parent/child hierarchy
This is worth stating plainly because it's a common source of confusion: a process's parent/child relationship (who created it) and its job membership (what group policy applies to it) are separate, independently tracked relationships. A process can be a "grandchild" three levels deep in a spawn tree and still be a direct member of the same job object as its top-level ancestor, precisely because breakaway policy propagated job membership down through every spawn — the job's membership list, not the parent/child chain, is what determines who gets torn down together.
A common mistake
Assuming that killing a parent process automatically kills its children is a persistent and incorrect intuition carried over from other systems' process models. On Windows, an orphaned child process generally keeps running perfectly normally after its parent exits — unless a job object with the right teardown policy was explicitly used to bind their lifetimes together. If you need guaranteed group teardown, a job object is the actual mechanism, not an assumption about parent/child behavior.
Where this connects
- Access tokens still applies independently to each process in a job — job membership constrains resources and lifecycle, not security identity.
- Processes & threads covers the individual process structure a job object groups several instances of.