Memory Management
Where values live and who reclaims them: stack versus heap, allocator design, tracing collection, reference counting and compile-time ownership. Interviewers probe where memory bugs begin.
part ofComputer science fundamentalsoverview, primer and where to startread it →on this pageshowhide
explore
- Stack vs Heap15 questions
- Address Space Regions5 questions
- Call Frames and Overflow5 questions
- What Forces Dynamic Allocation5 questions
- Allocation Strategies21 questions
- Size Classes and Fits5 questions
- Arenas and Object Pools6 questions
- Thread-Local Caches5 questions
- Internal and External Fragmentation5 questions
- Garbage Collection33 questions
- Liveness and Roots5 questions
- Mark-Sweep and Copying4 questions
- Young and Old Generations5 questions
- Tri-Colour Invariant4 questions
- Incremental and Concurrent Tracing4 questions
- Pause, Throughput, Footprint6 questions
- Weak References and Finalizers5 questions
- Reference Counting19 questions
- Increment and Decrement5 questions
- Strong, Weak and Unowned5 questions
- Cycles and Trial Deletion4 questions
- Atomic Update Cost5 questions
- Ownership and Lifetimes19 questions
- Scope-Bound Release5 questions
- Moving a Value5 questions
- Borrowing and Aliasing Rules5 questions
- Eliminated Bug Classes4 questions
- Leaks and Fragmentation24 questions
- What Keeps Objects Alive5 questions
- Retained Size Analysis5 questions
- Live Set and Churn5 questions
- Sizing Against a Limit5 questions
- Free But Unusable Space4 questions
- Android Developerroleanchors this topic
- Computer Scienceskillanchors this topic
- iOS Developerroleanchors this topic
- AI & Data Scientistrole
- Backend Developerrole
- Blockchain Developerrole
- Data Analystrole
- Data Engineerrole
- Forward Deployed Engineerrole
- Full Stack Developerrole
- Game Developerrole
- Java Backend Developerrole
- JavaScriptskill
- Kotlin Backend Developerrole
- Machine Learning Engineerrole
- Server-Side Game Developerrole
- Software Architectrole
questions
131 · 6 sectionsWhen you print the memory map of a running process, which regions does it contain and what does each hold?
basics
~20 sA process maps several regions with different rules: read-only code and constants, initialized static data, zero-filled static data, one growable heap, one stack per thread, and per-thread thread-local storage. Placement decides lifetime and who may write.
What does one frame on a thread's call stack hold, and why does returning from the call release it for free?
basics
~20 sA call frame holds that call's return address, saved registers, local variables and spilled temporaries, plus space for outgoing arguments. Returning moves the stack pointer back past the whole frame, so release is one instruction with no bookkeeping.
Why does storing through a pointer to a literal string constant fault, while storing into a heap block succeeds?
basics
~20 sA literal lives in the read-only constants region, mapped without write permission, so the hardware refuses the store. A heap block sits in a writable mapping, so the identical instruction succeeds. The region's permissions decide, not the pointer.
How do you estimate how deep a recursive call chain can go before it exhausts a thread's stack?
basics
~20 sDivide the thread's stack size by the average frame size: a 1 MiB stack with 80-byte frames allows roughly 13,000 nested calls. Frame size is the lever - adding a 256-byte local buffer per frame cuts that to about 3,100.
Before a compiler may place a new object on the stack instead of the heap, what must it prove?
basics
~20 sThat no reference to the object can be followed once the creating frame returns: it is never stored in longer-lived memory, returned, or published to another thread. Without that proof the object must go on the heap.
In a per-request scratch arena reset at the response boundary, how do allocation and release actually work?
basics
~20 sAllocation aligns one cursor, hands back its old position and advances it past the object, storing no per-object metadata. Nothing is released individually: at the response boundary the cursor is rewound to the start, which releases everything in the region at once.
Which fragmentation does an allocator harness measure when it reports 100 MB requested but 128 MB occupied, and which does it miss?
basics
~10 sThat 28 MB gap is internal fragmentation: bytes lost rounding each request up to a whole block. It cannot see external fragmentation, the free-but-scattered space between blocks, because nobody occupies those bytes.
When an allocator frees a block, how do boundary tags let it merge with both neighbouring free blocks in constant time?
basics
~20 sBoundary tags repeat each block's size and free flag in a header and a footer, so a released block reaches both address neighbours by arithmetic and merges with whichever are free — no list scan.
A heap allocator searching one free list can take the first block that fits or the smallest; what does each policy cost?
basics
~20 sFirst fit stops at the first adequate block, so the search is short but early splits leave small remainders near the list head. Best fit scans the whole list for the tightest block, paying a full walk to leave a smaller remainder.
How does a per-thread allocator cache make the common allocation path run with no synchronization at all?
basics
~20 sA per-thread allocator cache gives each thread its own free list per size class. Allocation pops that private list's head, and since no other thread can reach it, the pop needs no lock — only refill and flush synchronize.
A managed heap split into a young area and an older area rests on what observation about object lifetimes?
basics
~20 sMost objects die very young — the weak generational hypothesis. Splitting the heap by age lets a collector sweep the young area often and cheaply, where almost everything is already garbage, and touch the older area rarely.
In a tracing garbage collector, what is a root, and why must a collection start from the root set?
basics
~20 sA root is a reference the collector can find without tracing anything first — a running thread's stack slot or register, a global table entry, a handle registered by code outside the collected heap. Everything the program can still touch starts at one of them.
In three-colour marking (white unreached, grey reached but unscanned, black scanned), why may no black object reference a white one?
basics
~20 sBlack means already scanned, so the marker will not revisit it on its own. A reference from a black object to a white one is therefore a live object the trace never reaches — and would wrongly reclaim.
When a collector splits one heap trace into many short increments, what does the running program experience instead of one long stop?
basics
~20 sMany brief suspensions rather than one long one. The collector marks a bounded slice of the heap, hands control back, and resumes later from where it stopped. The longest pause shrinks; total collection work usually grows.
Why does adding heap headroom above a service's live set make a tracing collector cheaper per allocated byte?
basics
~20 sTracing cost follows the live set, not the free space, while each cycle reclaims everything above the live set. Extra headroom therefore spreads the same tracing work over far more allocation before the next cycle is needed.
Two objects in a counted heap hold references to each other and nothing outside can reach them; why is neither ever freed?
basics
~20 sEach object's count is held above zero by the other, so no decrement ever reaches zero. A count records whether anything points at an object, not whether anything reachable does, so an unreachable ring keeps itself alive.
In a reference-counted system, which events change an object's count, and what happens the moment that count reaches zero?
basics
~20 sEvery new owning handle to an object increments its count; every handle dropped or overwritten decrements it. At zero the object's cleanup runs, every handle it holds is released in turn, and its memory is reclaimed.
In a reference-counted object graph, what happens to a weak handle when the last owning handle to its object is dropped?
basics
~20 sIt reads as absent from that moment on. Only owning handles are counted, so the last one dropping destroys the object immediately; weak handles are not counted, cannot delay that, and are never allowed to yield destroyed storage.
A million-node counted chain loses its only head handle and every node is freed at once, so why can that hurt tail latency?
basics
~20 sOne decrement can destroy a whole structure. The thread that dropped the head handle runs a million cleanups, decrements and frees inline, in the middle of whatever request it was serving, so a cheap-looking assignment becomes an unbounded pause.
What is a borrow in an ownership discipline, and why can it never outlive the value's owner?
basics
~20 sA borrow is temporary non-owning access to a value someone else must release. It carries no release duty, so it stays valid only while that owner still holds the value; outliving the owner leaves it naming storage already reclaimed.
Why may many readers borrow the same value at once, while a writer must borrow it exclusively?
basics
~20 sReaders all observe one unchanging value, so overlapping them changes nothing. A writer can resize, move or half-update it, so any other reference alive at that moment could read a torn or stale view. Exclusivity for writers is what rules that out.
Why can a program built under a compile-time ownership discipline still leak heap memory with no unchecked code?
basics
~20 sA leak is memory that is still owned and still reachable — a cache that never evicts, a registration nobody cancels. The checks prove every access is valid; they say nothing about how long an owner chooses to keep a block.
Which memory-bug classes does a compile-time ownership discipline make unrepresentable rather than merely rarer?
basics
~20 sUse-after-free, double free, and dangling references into a moved or resized container become unrepresentable: single ownership plus lifetime-checked borrows reject them before the program builds. Leaks and logic errors are untouched, because keeping memory reachable is safe.
In a pipeline where one owning handle to a large chunk buffer carries the release duty, what does moving that handle do?
basics
~20 sA move transfers the release duty to the destination handle and leaves the source owning nothing. The block stays at the same address; only the small owning record is copied, so the cost is the same for 4 KiB and 64 MiB.
In a runtime that reclaims unreachable memory automatically, how can a program still leak memory?
basics
~20 sAutomatic reclamation frees only what nothing can reach. A leak there is memory that stays reachable from something live - an unbounded cache, a growing registry, a collection nobody trims - but will never be used again.
A container's memory ceiling kills a worker whose managed heap sits well under its configured maximum — why?
basics
~20 sA container ceiling counts every byte the whole process holds; the configured maximum heap bounds only one region inside it. Thread stacks, runtime metadata, allocator caches and buffers living outside the managed heap are charged against the ceiling too.
On a service's memory footprint chart, why is the post-collection floor the line you trend to decide whether it is leaking?
basics
~20 sThe post-collection floor is the live set: the bytes still reachable once the collector has finished. Peaks only record how much garbage piled up since the previous collection, so only a rising floor shows that memory is being retained.
A gateway's footprint saw-tooths between 1.2 GB and 3.0 GB every forty seconds while every post-collection floor sits at 1.2 GB — what is going on?
basics
~20 sThat is churn, not a leak. The flat 1.2 GB floor says the live set is constant; the 1.8 GB reclaimed every forty seconds says the service allocates roughly 45 MB a second of short-lived objects. The fix is allocation rate, not a retainer hunt.
In a heap snapshot, what does an object's retained size measure that its shallow size does not?
basics
~20 sShallow size is the bytes of the object itself: header, fields and its reference slots, but not their targets. Retained size adds everything that would become unreachable if that object did, so it measures what the object keeps alive.