C#

Memory & Garbage Collection

6 question(s)

How does garbage collection work in .NET?

Beginner
The GC automatically reclaims unreachable managed objects. It is generational (Gen 0/1/2): short-lived objects are collected cheaply in Gen 0, survivors are promoted.
var tmp = new byte[1024]; // Gen 0, collected quickly when unreachable
Real-world example Most request-scoped allocations die in Gen 0, keeping collections cheap.

What is the difference between managed and unmanaged resources?

Beginner
Managed resources are handled by the GC; unmanaged resources (file handles, sockets, native memory) are not and must be released via Dispose/finalizers.
using var file = File.OpenRead(path); // wraps an unmanaged handle
Real-world example Wrapping a native handle in an IDisposable so it's freed deterministically.

What is the IDisposable pattern and why implement it?

Intermediate
It provides deterministic cleanup of unmanaged resources via Dispose(), usually with using. Implement it when a type owns unmanaged or disposable resources.
public void Dispose() { _conn.Dispose(); GC.SuppressFinalize(this); }
Real-world example A repository that owns a DbConnection implements IDisposable so callers can release it promptly.

What is the difference between a finalizer and Dispose?

Intermediate
Dispose is deterministic cleanup you call; a finalizer runs non-deterministically during GC as a safety net. Finalizers delay collection, so prefer Dispose and suppress finalization.
~Handle() { ReleaseNative(); } // last resort
public void Dispose() { ReleaseNative(); GC.SuppressFinalize(this); }
Real-world example A wrapper around native memory uses a finalizer only as a backstop if Dispose was missed.

What causes managed memory leaks despite the GC?

Advanced
Objects stay reachable unintentionally: static references, un-removed event handlers, long-lived caches, or captured closures. The GC can't collect what is still referenced.
StaticCache.Add(bigObject); // never removed -> leak
Real-world example An ever-growing static dictionary cache slowly exhausts memory in a long-running service.

How do Span<T> and ArrayPool reduce GC pressure?

Advanced
Span<T> gives allocation-free views over existing memory (arrays, stack, native); ArrayPool<T> rents and returns buffers instead of allocating. Both cut Gen 0 churn on hot paths.
var buffer = ArrayPool<byte>.Shared.Rent(4096);
try { Read(buffer); } finally { ArrayPool<byte>.Shared.Return(buffer); }
Real-world example A high-throughput parser reuses pooled buffers to avoid allocating per request.