The Mechanic: Manual Memory & Pointers
🏗️ The Mechanic: Manual Memory & Pointers
Before we trust the Garbage Collector (GC) to manage our memory, we must understand how to manage it ourselves. In high-performance systems, “Managed” code can sometimes be a bottleneck.
1. The Stack vs. The Heap
In .NET, memory is divided into two primary zones:
- The Stack: Fast, local, and automatically cleaned up when a method returns. (Value Types).
- The Heap: Flexible, long-lived, but requires the GC to clean up. (Reference Types).
🛠️ Lab: Manual Stack Allocation
We can bypass the Heap entirely for small buffers using stackalloc.
public unsafe void ProcessData()
{
// Allocating memory directly on the stack
int* numbers = stackalloc int[5];
for (int i = 0; i < 5; i++)
{
numbers[i] = i * 10;
Console.WriteLine($"Value at pointer: {*(numbers + i)}");
}
}2. Pointers and unsafe code
To use pointers in C#, you must mark the code block as unsafe. This tells the compiler: “I am taking responsibility for memory safety.”
🧩 The Analogy: The Safety Harness
- Managed Code: You are in a modern car with airbags and automatic braking.
- Unsafe Code: You are on a motorcycle. You have more control and speed, but if you hit a wall (buffer overflow), there is no protection.
public unsafe void Swap(int* a, int* b)
{
int temp = *a;
*a = *b;
*b = temp;
}3. Fixed Memory (Pinning)
The GC likes to move objects around in the Heap to defragment it. If we have a pointer to an object, and the GC moves it, our pointer becomes “dangling” (points to garbage).
We use the fixed keyword to Pin an object in place.
byte[] data = new byte[100];
fixed (byte* p = data)
{
// The GC will NOT move 'data' while we are in this block.
p[0] = 0xFF;
}🧪 Professor’s Challenge: The Manual Buffer
Task: Build a CLI tool that uses stackalloc to parse a CSV line without creating a single string object.
- Use
ReadOnlySpan<char>to view the line. - Use pointers to identify the comma positions.
- Print the values directly from memory.