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.
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
RAM must cover the buffer pool, working memory, the page cache and overhead. A 200 GB heap leaves about 56 GB for the page cache, 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 double buffering. 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 reference counting, 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 live set 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
- External fragmentation in the allocator: 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.
- An unbounded intern table or dictionary: live state that never shrinks. Track its size over time.
- A reference held longer than the pipeline needs, such as a slow consumer pinning a shared buffer.
Fixes
An arena 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 LRU, whose list head becomes a contended cache line.
The rest
If you can afford about twice the metadata, 2Q or ARC, 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 Belady's MIN to see whether a 60% hit rate is a policy failure or a capacity failure. If capacity, use the five-minute rule to judge the value of more RAM before buying it.
Also
Size the pool on usable frames (minus pinned frames and dirty frames waiting on the log), and use explicit huge pages 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 dirty page 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 TLB shootdowns cost more as cores increase.
Economics
The five-minute rule: 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 pointer swizzling, 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 TLB 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 amplification, 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 over-commits: 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 utilization; 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 UDFs, 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 (1 − 0.05) + 2 × 0.05 × 50 = 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; LZ4 compression of the spill (about 3:1, which divides the dominant term by 3); and grant feedback, 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.
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 5× response time, and a fifth pushes it past 100%.
The feedback loop
Spilling makes queries take longer, so by Little's Law 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 queue 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.
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 shuffle output and forces recomputation upstream.
Watermarks
Two thresholds with hysteresis: 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, holistic aggregates, 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 1 / (1 − ρ) 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 Intel RDT, 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.