Types, Memory, and GC
Memory questions look like trivia but are graded as depth checks: does your mental model survive two follow-ups? Interviewers here are listening for repeated-myth answers.
The staple: value vs reference types
"What's the difference between a value type and a reference type?" Headline answer:
value types (int, struct, enum) are copied on assignment and compared by value;
reference types (class, string, arrays) assign a reference to a shared object. Then
the classic follow-up arrives: "So value types live on the stack, right?"
The strong candidate answers precisely: "Not necessarily β that's about the variable's
context, not the type. A struct field inside a class lives on the heap with its parent; a
local int in an async method can end up on the heap in the compiler-generated state
machine. 'Stack vs heap' is an implementation detail; the contract is copy semantics
vs reference semantics." Reciting "value types = stack" verbatim is a commonly repeated
myth β it's the answer of someone who memorized a blog post in 2012.
Second follow-up: "Is string a value type? It compares by value." No β it's a reference
type with value-like equality and immutability. Bonus point for mentioning that
immutability is why string behaves safely when shared.
Boxing β the question behind the question
"What is boxing and when does it bite?" Boxing wraps a value type in a heap object when
it's treated as object or a non-generic interface; unboxing casts it back. The modern honest
answer: generics killed most of it (List<int> doesn't box; the old ArrayList did), but it
still sneaks in β a struct cast to an interface it implements, string concatenation with
an int, or old non-generic APIs. Naming a current place it happens beats defining it
abstractly.
GC at answer-depth
You need two minutes of accurate garbage collector material, not a runtime internals lecture: the GC is generational β gen 0 (new, collected cheaply and often), gen 1 (survivors), gen 2 (long-lived, expensive to collect), plus the large object heap for big allocations like oversized arrays. The design bet: most objects die young.
The scenario version: "Memory climbs all day and never comes down β is the GC broken?"
Strong answer: almost certainly not β something is rooting objects. Prime suspects:
static collections and caches that only grow, event handlers never unsubscribed, and
IDisposable resources not disposed. "I'd take a memory snapshot and look at what's holding
the references" shows the verify habit. Saying "I'd call GC.Collect()" is a fail β it
treats the symptom and usually makes latency worse.
Practice prompts:
- Answer "struct vs class β when would you actually choose a struct?" with one real criterion (small, immutable, copied often) and one risk.
- Explain to a junior why a memory leak is possible in a garbage-collected language, in under a minute.
- "What does
IDisposablehave to do with the GC?" β answer, including what the GC does not manage.