Answer
Boxing wraps a value type in a heap-allocated object so it can be treated as a reference type (e.g., assigning an int to an object variable or adding it to a non-generic collection), incurring a heap allocation and copy. Unboxing extracts the value type back out of the boxed object, requiring a type check and copy. Both operations add measurable overhead compared to working with the value type directly, which is why generic collections (List<int> instead of ArrayList) are strongly preferred in modern .NET to avoid unnecessary boxing.
int number = 42;
object boxed = number; // boxing: heap allocation occurs
int unboxed = (int)boxed; // unboxing: type check + copy
// Generics avoid boxing entirely:
List<int> numbers = new(); // no boxing when adding ints
numbers.Add(42);Real-world example A performance audit of a hot code path discovers millions of unnecessary boxing allocations from storing int values in an old ArrayList-based cache, and switching to a generic List<int> or Dictionary<int, T> eliminates the boxing overhead entirely.