Skip to content
About
Main content

Scenarios

Longer problems, like those in senior system design interviews. A strong answer estimates with numbers first, names the mechanism, then recommends a fix and says what it costs.

Try each one before you open the answer.
1A 256 GB analytics server is killed by the out-of-memory killer every night. The JVM heap is 200 GB. A colleague suggests enabling swap. How do you respond?Show the answer

Draw the partition

A 200 GB leaves about 56 GB for the , thread stacks, direct buffers and the operating system, so any growth there pushes the machine over.

Why not swap

The kernel chooses what to swap by recency, so it will push out hash-table pages that merely look cold between probes. The job turns a clean failure into a crawl: hours instead of minutes.

Recommend

Size the four claimants explicitly: a heap well below total RAM, and separate budgets for off-heap buffers and the page cache. Decide whether direct I/O avoids . Move large, uniform, long-lived data off-heap, and ration the working memory of concurrent queries.

Failure mode

The risk of leaks and out-of-memory errors moves into your own accounting.

Read moreThe partition of RAMWhy the OS answer was rejectedOff-heap memory management

2A Java service keeps a 60 GB cache on the heap and freezes for 30 seconds every few minutes. Design the fix, and say when it would not be worth it.Show the answer

Estimate

60 GB as about 600 million small objects, traced at 10⁸–10⁹ references per second per thread, is seconds of marking per collection. Concurrent collectors move that cost onto the CPU, 10–20% of throughput, rather than removing it.

Fix

If the data is large, long-lived and uniform in shape, store it in a few large direct buffers with fixed-offset records, freed by explicit , and keep the rest of the heap small and tuned for short-lived objects.

Trade-offs

You now own layout, serialization and lifetime, and leaks and use-after-free bugs are silent.

When not worth it

When objects are small and short-lived (allocation in the young generation is a pointer bump, and copying across the boundary can cost more), or when the is already small and the problem is allocation churn: tune the young generation and stop. On JDK 8 the low-pause collectors are not available, so moving off-heap pays at a smaller live set.

Read moreOff-heap memory managementGC tuning versus manual management

3A process's resident memory grows for days while the heap in use stays flat. How do you diagnose and fix it?Show the answer

Hypotheses and tests

  1. in the : free memory exists but not in contiguous pieces, common in long-running workloads with mixed sizes. Compare resident memory with live bytes from the allocator's statistics.
  2. An unbounded intern table or dictionary: live state that never shrinks. Track its size over time.
  3. A reference held longer than the pipeline needs, such as a slow consumer pinning a shared buffer.

Fixes

An per execution phase with an explicit reset point (bounded fragmentation and cheap allocation, paid for in peak memory held); dictionaries with a cap and a fallback to plain encoding; and audits of who owns each buffer.

Trade-off

Arenas need a clear phase boundary; without one, you have a leak with a bump pointer.

Read moreArenas and region allocationString interning and dictionary reuseColumnar memory pooling

4Choose a replacement policy for a database buffer pool on a 96-core server, serving both dashboard point lookups and nightly full scans.Show the answer

Scans

Declare them: give scans a ring of buffers so they never enter the main pool. That beats any adaptive policy.

Cores

With dozens of cores hitting the pool at once, synchronization on the hit path dominates, so use Clock (or a sharded Clock) rather than , whose list head becomes a contended .

The rest

If you can afford about twice the metadata, or , with ghost entries, protects pages seen twice and adapts between recency and frequency. Check licensing, and note that ARC still changes lists on hits.

Measure the ceiling

Replay a trace against to see whether a 60% is a policy failure or a capacity failure. If capacity, use the to judge the value of more RAM before buying it.

Also

Size the pool on (minus pinned frames and dirty frames waiting on the log), and use explicit with transparent huge pages off.

Read moreScan resistance by declarationClockLRU-K, 2Q and ARCUsable frames

5A database engineer proposes memory-mapping the data file and letting the operating system manage it, because RAM is cheap. Argue the case against, with numbers.Show the answer

Correctness first

Write-ahead logging needs the engine to decide when a may reach disk. With mmap the kernel decides, so the rule cannot be enforced.

Latency

Page-fault I/O is invisible to the engine, so stalls happen inside critical sections that assumed memory speed; errors arrive as SIGBUS; and cost more as cores increase.

Economics

The : with 8 KB pages (128 per MB), and illustrative prices of $0.003 per access-per-second and $0.003 per MB of RAM, the break-even is (128 × 0.003) ÷ 0.003 = 128 seconds. Pages touched every few minutes belong in RAM and colder ones do not, so some residency policy is always needed, however cheap RAM gets.

Concede

The engineering complaint, buffer-pool overhead, is real. It is answered by , not by deleting the pool.

Read moreTwo live claimsPinning and unpinning

6A 100 GB buffer pool shows high CPU time in address translation. Diagnose and fix.Show the answer

Estimate

100 GB ÷ 4 KB ≈ 26 million page-table entries, while a of about 1,500 entries covers only about 6 MB. Nearly every access to a new page is a TLB miss, followed by a dependent page-table walk of 20–100 cycles.

Fix

Back the pool with 2 MB huge pages, which multiply the TLB's reach about 500×, to roughly 3 GB for 1,536 entries.

Caveat

Use explicit, reserved huge pages and turn transparent huge pages off: their background compaction causes stalls of tens of milliseconds, improving the mean but ruining the variance.

Verify

With TLB-miss counters (perf stat) before and after. The pool's own page size (4–32 KB) is a separate decision, about read , not the TLB.

Read morePage sizeThe operational caveat

7At 9 a.m. on Monday, a tiny lookup query is killed for lack of memory while a giant join survives. Meanwhile another cluster is queuing queries with 60% of its memory idle. Diagnose and fix both.Show the answer

The first cluster

It : queries allocate as they go, and the victim is whoever allocates last, not whoever holds the most. Add grants and an admission gate that counts bytes, so failures happen at admission, with a clear cause.

The second cluster

It over-reserves: grants come from estimates an order of magnitude too high, so memory is reserved and never touched. Measure actual peak against grant for each plan, feed that back to shrink future grants, and size grants at merge-pass boundaries.

Both

Cap memory per query to limit the damage any one can do. The trade-off is isolation against ; because Monday peaks are correlated (a batch window), reservation rather than over-commit is the right position. Also look for memory holders the system cannot see, such as , which set the size of the reserve.

Read moreMemory grants and reservationsAdmission control by memory footprintWhere the grant number comes fromMemory pressure signalling

8A join spills only 5% of its build side but runs 6 times slower. Your manager suggests buying faster disks. How do you respond?Show the answer

Estimate

With memory at 100 GB/s and NVMe at 2 GB/s, the ratio r is 50, so = 5.95, about 6×. The result is expected, not a bug.

Disks

Faster disks help only in proportion to r.

Better options, cheapest first

A larger grant, at the next pass boundary; compression of the (about 3:1, which divides the dominant term by 3); and , so the next run is sized right.

Check the deployment

If the spill disk is network-attached, r is about 500 and the same spill costs about 51×.

Recommend

Compression and feedback first, hardware last.

Read moreWhat spilling actually costsWhere spill goesThe grant is a point on a curve

9A nightly aggregation over meter IDs never finishes. One meter ID has 400 million rows. What do you do?Show the answer

Diagnose

The terminal case of skew: no hash function can split one key, so recursive partitioning never converges.

Check the algebra first

If the aggregate is SUM, COUNT, MIN or MAX, aggregate partially: each group's state is constant-sized, and nothing needs to spill.

If it is holistic

For an exact median or distinct count: fall back to sort-merge for the oversized partition (it always terminates, at the cost of a log factor and a second code path); plan for skew by detecting hot keys from statistics and handling them separately (relying on statistics that are weakest exactly at the tail); or use an approximate sketch.

Recommend

Reformulating first: it costs nothing.

Read moreSkew breaks itThe escapes, each with its price

10Under heavy load, every query spills at once and latency collapses, even though memory admission control worked. Why, and what do you change?Show the answer

Diagnose

Memory was gated, but spill bandwidth was not. Under correlated pressure, every query spills to the same local device. With a 1.5 GB/s drive and 0.3 GB/s per query, four queries put it at 80% utilization, a , and a fifth pushes it past 100%.

The feedback loop

Spilling makes queries take longer, so by more are in flight holding grants: the relief feeds the pressure.

Fix

Limit how many queries may spill at once, sized to keep the device below about 70% utilization, and the rest. Compress spill, and consider a kill rule at a hard watermark.

Trade-off

Some queries wait instead of crawling, but the device does not collapse.

Read moreGraceful degradation: the honest version

11Design the response for when memory runs out and the operating system's out-of-memory killer starts killing executors.Show the answer

Principle

Fail a query before the kernel fails a process: losing an executor destroys cached blocks and and forces recomputation upstream.

Watermarks

Two thresholds with : at the soft one, ask consumers to spill; at the hard one, stop admitting, then kill. Size the reserve from spill latency and from memory holders the system cannot see (UDFs, libraries).

Know the candidates

Keep an inventory of operators that cannot spill (unbounded window frames, , UDF state, broadcast hash tables): they are the kill candidates.

Choose the victim by policy

Killing the requester loses the least work; killing the largest holder frees the most. Each just moves the cost somewhere.

Close the loop

Feed kills back into grant sizing, so the retry gets a larger grant.

Read moreMemory pressure signallingUnspillable state and the kill decisionThe retry trap

12A latency-sensitive dashboard slows down whenever a scan-heavy tenant runs on the same machine, yet no memory metric changes. Explain, and decide what to do.Show the answer

Explain

Container memory limits cap capacity, not memory bandwidth or the shared last-level cache. A scan with no reuse evicts the shared cache and saturates the memory controller, so the dashboard's latency rises along the curve while both tenants stay within their limits.

Options

Put the workloads on different sockets or nodes (simple, costs utilization); limit the scan's threads; or use hardware partitioning of cache and bandwidth, such as , which exists but is rarely used outside very large fleets.

Recommend

Isolate by placement now, and measure memory bandwidth per socket so the problem becomes visible.

Read moreCapacity isolation is not bandwidth isolation