← Back to Articles         
Managed vs Unmanaged Code, Value Types vs Reference Types, Boxing and Unboxing

Managed vs Unmanaged Code, Value Types vs Reference Types, Boxing and Unboxing

Published on 12 Oct 2026     11 min read C#
C# Fundamentals
 

C# Memory Management – Managed vs Unmanaged Code, Value Types vs Reference Types, Boxing and Unboxing

These three concepts explain how C# executes code, stores data in memory, and converts between value types and reference types.

They are important for understanding the CLR, Garbage Collection, memory allocation, and application performance.

 

1. What is the difference between managed and unmanaged code?

What is managed code?

Managed code is code that executes under the supervision of the Common Language Runtime (CLR) in .NET.

The CLR provides runtime services such as memory management, Garbage Collection, exception handling, and type safety.

Example:

public class Employee
{
    public string Name { get; set; }
}

Employee emp = new Employee();
emp.Name = "John";

Console.WriteLine(emp.Name);

Explanation:

  1. The Employee class is written in C#.

  2. The C# compiler normally compiles the code into Intermediate Language (IL).

  3. The CLR executes the code, typically using JIT compilation to generate native instructions.

  4. The Employee object is allocated in managed memory.

  5. The Garbage Collector automatically reclaims its memory when the object becomes unreachable.

Managed code execution flow:

       C# Source Code
              |
              v
        C# Compiler
              |
              v
   Intermediate Language (IL)
              |
              v
             CLR
              |
              v
        JIT Compiler
              |
              v
       Native Machine Code
              |
              v
          Execution

What is unmanaged code?

Unmanaged code is code that executes outside CLR supervision.

Native applications written in C or C++ are common examples. Memory management depends on the native language, libraries, and runtime.

Example (C):

int* ptr = (int*)malloc(sizeof(int));

*ptr = 100;

printf("%d", *ptr);

free(ptr);

Explanation:

  1. malloc() allocates memory.

  2. ptr stores the address of the allocated memory.

  3. The value 100 is stored at that address.

  4. free() explicitly releases the allocated memory.

  5. Forgetting free() can cause a memory leak.

Managed Code vs Unmanaged Code

Managed Code

Unmanaged Code

Executes under CLR

Executes outside CLR

CLR manages managed memory

Memory management depends on native code/runtime

Supports automatic Garbage Collection

Does not use .NET GC automatically

CLR provides type-safety checks

Safety depends on language and implementation

Examples: C#, VB.NET

Examples: native C, C++

Can call native libraries

Can expose functions to managed applications

Can managed code call unmanaged code?

Yes. C# can call native libraries using Platform Invocation Services (P/Invoke).

Example:

using System.Runtime.InteropServices;

class Program
{
    [DllImport("kernel32.dll")]
    static extern uint GetCurrentProcessId();

    static void Main()
    {
        uint processId = GetCurrentProcessId();

        Console.WriteLine(processId);
    }
}

Here, managed C# code calls a native Windows API function.

Key Points

  • Managed Code: Executes under CLR supervision.

  • Unmanaged Code: Executes outside CLR supervision.

  • CLR: Provides memory management, type safety, and exception handling.

  • Garbage Collector: Automatically reclaims unreachable managed objects.

  • Manual Cleanup: Unmanaged memory may require explicit release.

  • P/Invoke: Allows C# applications to call native libraries.

  • Important: Managed code can still use unmanaged resources, which may require Dispose() or other explicit cleanup.

Interview Answer:

Managed code executes under the CLR, which provides services such as automatic garbage collection, exception handling, and type safety. Unmanaged code executes outside CLR supervision, and its memory management depends on the native runtime or programmer. C# can interact with unmanaged code using P/Invoke.

 

2. What is the difference between value types and reference types?

In C#, data types are broadly classified into two categories:

  1. Value Types

  2. Reference Types

The main difference is how data is stored, copied, and shared between variables.

What is a value type?

A value type stores its actual value directly.

When one value-type variable is assigned to another, the value is copied.

Examples:

  • int

  • double

  • bool

  • char

  • decimal

  • struct

  • enum

Example:

int a = 10;

int b = a;

b = 20;

Console.WriteLine(a); // 10
Console.WriteLine(b); // 20

Explanation:

  1. a is initialized with 10.

  2. b = a copies the value 10 into b.

  3. b = 20 changes only b.

  4. The original variable a remains unchanged.

Memory representation (conceptual):

Step 1:
-------

int a = 10;

+-------------+
|      a      |
|     10      |
+-------------+


Step 2:
-------

int b = a;

+-------------+       +-------------+
|      a      |       |      b      |
|     10      | ----> |     10      |
+-------------+ Copy  +-------------+


Step 3:
-------

b = 20;

+-------------+       +-------------+
|      a      |       |      b      |
|     10      |       |     20      |
+-------------+       +-------------+

Result:
a = 10
b = 20

Both variables have independent values.

What is a reference type?

A reference type variable stores a reference to an object.

When one reference variable is assigned to another, the reference is copied, not the object.

Examples:

  • class

  • string

  • array

  • object

  • interface

  • delegate

Example:

public class Employee
{
    public string Name { get; set; }
}

Employee emp1 = new Employee();

emp1.Name = "John";

Employee emp2 = emp1;

emp2.Name = "David";

Console.WriteLine(emp1.Name); // David
Console.WriteLine(emp2.Name); // David

Explanation:

  1. emp1 references an Employee object.

  2. emp2 = emp1 copies the reference.

  3. Both variables now reference the same object.

  4. Changing Name through emp2 modifies that shared object.

  5. Therefore, emp1.Name also returns "David".

Memory representation (conceptual):

Step 1:
-------

Employee emp1 = new Employee();
emp1.Name = "John";

  emp1
    |
    v
+--------------------+
| Employee Object    |
| Name = "John"      |
+--------------------+


Step 2:
-------

Employee emp2 = emp1;

  emp1         emp2
    |            |
    +------+-----+
           |
           v
+--------------------+
| Employee Object    |
| Name = "John"      |
+--------------------+


Step 3:
-------

emp2.Name = "David";

  emp1         emp2
    |            |
    +------+-----+
           |
           v
+--------------------+
| Employee Object    |
| Name = "David"     |
+--------------------+

Result:
emp1.Name = "David"
emp2.Name = "David"

Both variables reference the same object.

Value Types vs Reference Types

Value Types

Reference Types

Store actual values directly

Store references to objects

Assignment copies the value

Assignment copies the reference

Independent values after assignment

Multiple references can share one object

Cannot normally contain null

Can contain null

Examples: int, bool, struct

Examples: class, array, string

May be stored on stack, heap, or registers

Objects are typically allocated on the managed heap

Important: Are value types always stored on the stack?

No.

This is a common interview misconception.

Consider:

public class Employee
{
    public int Age { get; set; }
}
Employee emp = new Employee();

emp.Age = 30;

Here:

  • Employee is a reference type.

  • Age is a value type.

  • The integer value is stored as part of the Employee object, which is typically allocated on the managed heap.

       emp (Reference)
             |
             v
     Managed Heap
+-----------------------+
| Employee Object       |
|                       |
| Age = 30              |
| (Value Type Field)    |
+-----------------------+

Important: Value type does not mean stack memory, and reference type does not simply mean heap memory. The primary distinction is value semantics versus reference semantics.

Special case: Why does string behave differently?

string is a reference type, but it is immutable.

Example:

string a = "Hello";

string b = a;

b = "World";

Console.WriteLine(a); // Hello
Console.WriteLine(b); // World

When b is assigned "World", it references a different string. The original "Hello" string is not modified.

Key Points

  • Value Type: Stores actual data directly.

  • Reference Type: Stores a reference to an object.

  • Assignment: Value types copy values; reference types copy references.

  • Modification: Changing a copied value type does not affect the original.

  • Shared Object: Changes through one reference can be visible through another reference.

  • Memory: Value types are not always stored on the stack.

  • Examples: int, bool, struct are value types; class, string, array are reference types.

  • Null: Value types require nullable syntax (int?) to represent null.

  • Special Case: string is an immutable reference type.

Interview Answer:

Value types store actual data, and assigning one value-type variable to another creates an independent copy. Reference types store references to objects, and assignment copies the reference. Therefore, multiple reference variables can point to the same object, and modifications to that object are visible through all its references.

 

3. What is boxing and unboxing in C#?

Boxing and unboxing are operations used to convert between value types and boxed objects.

What is boxing?

Boxing is the process of converting a value type into an object or an implemented interface reference.

During boxing, a new object is created on the managed heap, containing a copy of the value.

Example:

int a = 100;

object obj = a; // Boxing

Explanation:

  1. a contains the integer value 100.

  2. object obj = a performs boxing.

  3. A new boxed object is allocated on the managed heap.

  4. The value 100 is copied into the boxed object.

  5. obj references that object.

Memory representation:

Before Boxing:
--------------

int a = 100;

+----------------+
| int a          |
| Value = 100    |
+----------------+


After Boxing:
-------------

object obj = a;

+----------------+       +--------------------+
| int a          |       | Boxed int Object   |
| Value = 100    | ----> | Value = 100        |
+----------------+ Copy  +--------------------+
                                   ^
                                   |
                              object obj

The boxed object is allocated on the managed heap.

What is unboxing?

Unboxing is the process of extracting a value type from a compatible boxed object.

An explicit cast is required.

Example:

object obj = 100;

int b = (int)obj; // Unboxing

Explanation:

  1. obj references a boxed integer containing 100.

  2. (int)obj checks whether the boxed object contains the expected value type.

  3. The integer value is extracted and copied into b.

  4. b now contains an independent integer value.

Memory representation:

Before Unboxing:
----------------

object obj
    |
    v
+--------------------+
| Boxed int Object   |
| Value = 100        |
+--------------------+


After Unboxing:
---------------

int b = (int)obj;

+--------------------+       +----------------+
| Boxed int Object   |       | int b          |
| Value = 100        | ----> | Value = 100    |
+--------------------+ Copy  +----------------+

The value is copied into b.
The boxed object remains unchanged.

Complete example of boxing and unboxing

int a = 10;

// Boxing
object obj = a;

// Unboxing
int b = (int)obj;

b = 20;

Console.WriteLine(a);   // 10
Console.WriteLine(obj); // 10
Console.WriteLine(b);   // 20

Explanation:

  • a initially contains 10.

  • Boxing copies 10 into a new object.

  • Unboxing copies the boxed value into b.

  • Changing b to 20 does not modify a or the boxed object.

Boxing vs Unboxing

Boxing

Unboxing

Value type → Boxed object

Boxed object → Value type

Implicit conversion

Explicit cast required

Creates a boxed object

Extracts the contained value

Allocates managed heap memory

Does not itself require a new boxed allocation

Example: object o = 10;

Example: int x = (int)o;

Can unboxing cause an exception?

Yes. Incorrect unboxing can cause InvalidCastException.

Example:

object obj = 100;

double d = (double)obj;

Result:

System.InvalidCastException

Why?

The boxed object contains an int, not a double.

Although an integer can normally be converted to a double, direct unboxing requires the correct underlying value type.

Correct approach:

object obj = 100;

int number = (int)obj;

double d = number;

Alternatively:

double d = Convert.ToDouble(obj);

Why should we avoid unnecessary boxing and unboxing?

Boxing introduces an object allocation, which can increase memory usage and Garbage Collector workload.

Example using ArrayList:

using System.Collections;

ArrayList numbers = new ArrayList();

numbers.Add(10); // Boxing
numbers.Add(20); // Boxing

int a = (int)numbers[0]; // Unboxing

Better approach using List<int>:

List<int> numbers = new List<int>();

numbers.Add(10);
numbers.Add(20);

int a = numbers[0];

List<int> avoids boxing for normal integer storage and retrieval.

Key Points

  • Boxing: Converts a value type into a boxed object.

  • Unboxing: Extracts the value type from a compatible boxed object.

  • Implicit Conversion: Boxing happens automatically.

  • Explicit Conversion: Unboxing requires a cast.

  • Memory Allocation: Boxing allocates an object on the managed heap.

  • Copy: Boxing and unboxing copy the value.

  • Performance: Excessive boxing can increase allocations and GC overhead.

  • Exception: Incorrect unboxing can throw InvalidCastException.

  • Best Practice: Use generic collections such as List<int> to avoid unnecessary boxing.

Interview Answer:

Boxing converts a value type into an object by copying the value into a boxed object on the managed heap. Unboxing extracts the value from the boxed object using an explicit cast. Boxing can introduce memory allocations and performance overhead, so unnecessary boxing and unboxing should be avoided by using generics.

 

Quick Interview Revision – All Three Concepts

Concept

Important Point

Managed Code

Executes under CLR supervision

Unmanaged Code

Executes outside CLR supervision

Garbage Collector

Reclaims unreachable managed objects

Value Type

Assignment copies the actual value

Reference Type

Assignment copies the object reference

Boxing

Value type → Boxed object

Unboxing

Boxed object → Value type

Boxing Memory

Allocates an object on the managed heap

Boxing Performance

May increase allocations and GC workload

Avoid Boxing

Prefer generics such as List<int>

Frequently Asked Follow-up Interview Questions

  1. Are value types always stored on the stack? No. Their storage depends on context.

  2. Are reference-type objects always stored on the heap? Typically, but runtime optimizations may vary.

  3. Can a reference type be null? Yes.

  4. Can a value type be null? Yes, using nullable value types such as int?.

  5. Is string a value type? No, it is an immutable reference type.

  6. Does boxing create a new object? Yes.

  7. Does unboxing require an explicit cast? Yes.

  8. Can unboxing throw an exception? Yes, InvalidCastException.

  9. How can boxing be avoided? Use generics and strongly typed APIs.

  10. Can managed code call unmanaged code? Yes, using P/Invoke or other interoperability mechanisms.

Final takeaway: Managed versus unmanaged code concerns CLR supervision. Value versus reference types concerns copying and sharing semantics. Boxing and unboxing concern converting between value types and boxed objects.

← Back to Articles