Skip to content
Search lessons, topics, tests…
Esc

    ↑ ↓ moveEnter openEsc close

    Module 1 · How Boxing and Unboxing Work · Lesson 2 of 21

    Boxing step by step

    2.1 The smallest example

    C#
    int number = 42;
    object boxed = number;
    // Implicit boxing conversion.
    number = 100;
    Console.WriteLine(number); // 100
    Console.WriteLine(boxed);
    // 42

    The assignment to boxed does not make an alias to the local variable number. It snapshots the current four payload bytes into a new object. Changing the local later changes only the local.

    STEP 1 - before boxing

    Thread stack / JIT local state

    Text
    +----------------------------------+
    | number                           |
    |                                  |
    | int32 bytes = 2A 00 00 00        |
    |                                  |
    +----------------------------------+

    Managed heap

    Text
    Gen 0 allocation area:
    [ free ... ]

    STEP 2 - execute: object boxed = number;

    Thread stack / roots

    Managed heap - Gen 0

    Text
    +----------------------------------+
    allocation start
    | number = 42                      |
    |
    +---------------------------+ -8
    | boxed
    -------------------------------| object header
    |
    +----------------------------------+
    +---------------------------+
    0 <- boxed
    | MethodTable* : Int32 box |
    +---------------------------+ +8
    | int32 payload = 42
    |
    +---------------------------+ +12
    | padding
    |
    +---------------------------+ total commonly 24 B

    STEP 3 - number = 100;

    The local changes. The independent boxed payload remains 42.

    2.2 Representative allocation arithmetic

    On a typical 64-bit CoreCLR process, a boxed int commonly consumes the minimum object size: approximately 24 bytes.

    ComponentLogical bytesRepresentative aligned bytes
    Object header before managed reference88
    MethodTable pointer88
    int payload44
    Alignment / minimum-object padding04
    Total allocation2024

    That is roughly six times the four payload bytes, before counting the reference slot that stores the box elsewhere. In an object[] on x64, the element slot adds another 8 bytes.

    Cost model for one box

    • Time: O(1). Allocate, initialize metadata, copy the value payload, return a reference.
    • Allocation: Usually one managed object. Payload size is rounded for object alignment and minimum size.
    • GC impact: One more object to discover, age, possibly promote, and eventually reclaim. A box with no reference fields is cheap to scan, but it still occupies heap space and contributes to collection frequency.
    • Locality: The value is no longer inline with neighboring values. Consumers follow a reference to a separate object.

    2.3 Boxes preserve runtime type, not source spelling

    C#
    byte small = 7;
    object a = small;
    // Boxed System.Byte.
    object b = (int)small;
    // Numeric conversion first, then boxed System.Int32.
    Console.WriteLine(a.GetType()); // System.Byte
    Console.WriteLine(b.GetType()); // System.Int32

    The object records the exact boxed value type through its MethodTable. This exactness becomes crucial during unboxing.

    Under The Hood

    • IL stack transition: Conceptually, box T consumes a value of type T from the evaluation stack and pushes an object reference.
    • MethodTable: The boxed object points to runtime metadata for the boxed value type. The runtime can therefore answer GetType(), dispatch overridden methods, and obtain the GC layout for a boxed struct containing references.
    • Copy size: For a struct, all instance fields are copied into the payload. A large struct makes boxing more expensive than boxing a four-byte integer.
    • Write barriers: If the boxed struct contains managed-reference fields, initializing those references must obey GC write-barrier rules. The MethodTable’s GC descriptor tells the collector which payload words are references.
    Sign in to mark lessons done and keep your place in the course.Sign in