skip to content

Two engines divide a worker's budget differently - one shared pool, one reserved block. What does each design buy and cost?

level: seniorimportance: should knowfreq 45%

answer

  1. the line is not in the same place
  2. flexibility against predictability
  3. unused room: shared or stranded
  4. packed block avoids reclamation pauses
  5. a recipe does not travel between engines

basics

~20 s

A shared pool divided at runtime lets operator work and kept results take room the other is not using, at the price of one squeezing the other. A fixed reserved block is predictable but strands room it does not need.

solid answer

~50 s

Engines genuinely disagree here, and the disagreement is the answer. One design keeps a **single pool** and divides it at runtime between the room operators borrow while they run and the results the job asked it to keep, with borrowing in both directions: nothing is stranded, but a kept result can be evicted when operators need room, and operators can find less room than the headline budget suggests. Another **reserves a fixed block** the engine allocates and interprets itself as packed bytes, sized before any record arrives, leaving the rest of the process to the host language runtime: the boundary is predictable and free of reclamation pauses inside the block, but room reserved and unused is idle, and you now size two things. A third, older shape holds almost no kept results at all. So a recipe does not travel.

go deeper

for a junior

Recall only that a worker's memory is cut into regions before anything runs, and that different engines cut it in different places, so a number someone gives you belongs to one engine.

for a middle

Explain the mechanics of each design: what a runtime-divided pool does with room one use is not taking, and what a reserved block gives up in exchange for a boundary that does not move.

for a senior

Demonstrate that you reason about the failure signature each design produces, and that you refuse to transplant a ratio; say which boundary was crossed before proposing anything.

for a principal

The call you own is which design your platform standardises on and what the organisation inherits with it - stranded capacity and two numbers to size, or high utilisation and runs that behave differently depending on what was pinned.

## Why this question exists at all A **worker** - one operating-system process running some of the job's work, owning memory nothing else can borrow - has to decide, before any record arrives, how much of its budget may go to operators that are running and how much to results the job asked it to hold. Engines of this class answer differently, and the difference is not cosmetic: it changes what runs out first, what the failure looks like, and whether a number that worked on one engine means anything on another. ## Design one: a single pool divided at runtime The engine keeps one accounted pool and assigns it dynamically between two uses: - **Operator working memory** - room borrowed while a step runs, for sorting, for the in-memory table an aggregation builds with one entry per distinct key, for the built side of a join, and returned when the step ends. - **Retained-result memory** - room holding intermediates the job pinned so later steps read them instead of recomputing the branch above. Because the line moves, room that one use does not need is available to the other. What you buy is utilisation. What you pay is coupling: a pinned result can be dropped under pressure from running operators, and a job with a lot pinned leaves operators working against less room than the headline budget suggests. Two runs of the same program can therefore behave differently depending on what was pinned when. ## Design two: a fixed block the engine manages itself The engine reserves a block up front and manages it as **engine-managed binary records** - a packed byte layout it allocates and interprets itself, so a field is read at a known offset rather than by following a pointer to an object. Everything else in the process - ordinary language objects, buffers, user-supplied code - lives outside that block, under the host language runtime. What you buy is predictability. The block does not shrink because something else grew; an operator that exceeds it behaves deterministically, typically by **spilling** - writing part of its working set out to disk attached to the worker and reading it back to finish the step; and the packed layout largely avoids **automatic reclamation** inside the block, the runtime's periodic sweep for objects nothing refers to any more, which stops the worker's own work for as long as it takes. What you pay is stranding and arithmetic: a block sized for the heaviest operator is idle when that operator is not running, and the rest of the process now needs sizing of its own. ## Design three: hardly any of the above The oldest shape in this class - a two-phase disk-to-disk model - has almost no notion of a kept result. Each unit of work gets a working buffer of fixed size, fills it, sorts and writes it out, and the memory story is essentially *how big is the buffer and how often does it spill*. Any question phrased as *how does the engine balance kept results against operator work* is unanswerable on it, which is exactly why this subject is stated as a disagreement rather than as one layout. ## Side by side | | shared pool, divided at runtime | fixed reserved block | |---|---|---| | unused room | goes to the other use | stays reserved and idle | | predictability | lower: depends what is pinned | higher: the boundary does not move | | a kept result under pressure | may be dropped to free operators | competes outside the block, if it exists at all | | reclamation pauses | felt across the whole pool | largely avoided inside the block | | what you must size | one number, plus the uncounted region | two numbers, plus the uncounted region | ## What follows for an engineer 1. **Never carry a memory recipe across engines.** A fraction, a ratio or a rule of thumb encodes where one engine's line falls. On an engine that draws it elsewhere the same numbers move pressure to a different place, usually the one you were not watching. 2. **Say which boundary you mean.** The region boundary an operator spills at is crossed routinely and is not a failure. The ceiling the platform applies to the whole process is fatal. They are different lines and only one of them is the engine's. 3. **Expect a different failure signature.** On a shared pool, memory trouble often shows as kept results disappearing and branches being recomputed. On a reserved block, it shows as an operator spilling at a boundary while the rest of the process looks comfortable - or the reverse, the process running short while the block sits half used. ## The sentence to avoid *The engine splits its memory between execution and storage.* It is true of one lineage and false of the others, and it is the most common way this subject is taught wrongly. State it as *some engines divide one pool at runtime, others reserve a fixed block and leave the rest to the host runtime, and one older model barely holds results at all* - then say which you are on.

  • Why does a memory recipe carried from one engine to another often make things worse?
    Because the recipe is a statement about where that engine drew its region lines and what its accounting covered. Applied to an engine that divides the budget differently, the same numbers shift pressure somewhere else - typically into the region nobody was watching, such as the bytes the engine never counted - and the new failure looks unrelated to the change.
  • On a design with a fixed reserved block, how can a worker run short while that block is half empty?
    The block is only one region of the process. Ordinary language objects, network and native buffers, and anything a user-supplied function allocates live outside it, and the ceiling the platform enforces counts the whole process. So the reserved block being comfortable says nothing about the rest of the footprint.
  • What does a shared pool do when operators need room that pinned results are occupying?
    Designs that share one pool generally let running operators reclaim it, dropping kept results under pressure rather than failing the step - which means the branch that produced them is recomputed later. The details of that trade, and of the pin nobody released, belong to the subject of reusing a computed result.

saying these in an interview costs you the question

  • Assumes every engine splits one pool between operator work and kept results
  • Thinks a fixed reserved block can spread into the rest of the process
  • Believes unused kept-result room is always available to operators
  • Applies a memory ratio learned on one engine to another unchanged
  • Confuses the boundary an operator spills at with the process ceiling
  • Treats packed binary records as universal across this class of engine