Dataslope logoDataslope

How Programs Execute

A beginner-friendly tour of what actually happens between writing C# source code and seeing output on the screen

When you click Run in this site's playground, a lot more happens than "the code goes." This page is a tour of every stage, in plain language. Understanding this picture is the difference between feeling like programming is magic and feeling like you know what's going on.

We'll keep it conceptual — you don't need to memorize bytecodes or CPU instructions, just build the mental model.

The big picture

There are five real "things" in that diagram, plus the CPU. Let's walk through them.

1. Source code

This is what you write.

Code Block
C# 13

It's text. To the computer, it is meaningless until something translates it. The translator is called the compiler.

2. The compiler turns source into Intermediate Language

For C#, the compiler is called Roslyn. Roslyn takes your .cs files and produces a .dll (or .exe) containing a lower-level language called CIL (Common Intermediate Language, sometimes "IL" for short).

CIL is not the machine code your CPU runs. It is a portable, more abstract instruction set designed for the .NET runtime. The reason to compile to CIL (instead of directly to your CPU's machine code) is that the same .dll can then run on any machine, regardless of its CPU architecture.

You can think of CIL as a "halfway language": low-level enough that the runtime can run it efficiently, but high-level enough that it's not tied to one CPU.

3. The runtime loads and verifies your program

When you run your program, the .NET runtime (the CLR — Common Language Runtime) loads the .dll and does a number of things before any of your code executes:

  • Type checks. The runtime verifies that your program's types are consistent — for example, you're not trying to use a number as a method.
  • Security checks. Make sure the program isn't trying to do something it isn't allowed to.
  • Memory setup. Reserve a chunk of memory for the stack and the heap (we'll meet both shortly).

If you ever see Could not load file or assembly or similar errors before your program runs at all, this stage is usually where the trouble is.

4. JIT compilation: IL → native CPU code

Right before your code is about to run, the runtime uses a Just-In-Time (JIT) compiler to turn IL into the real machine code for the CPU you're on.

This is why your first run might feel slightly slow: the JIT is working. Subsequent calls to the same method are essentially free because the machine code has been cached.

5. Memory: the stack and the heap

While your program runs, it uses memory. The runtime divides that memory into two big regions, and you'll hear about both for the rest of your career.

  • The stack holds the bookkeeping for each method call: its local variables, its parameters, and where to return when it's done. It's called a stack because method calls pile on top of each other and pop off in reverse order.
  • The heap holds long-lived objects whose lifetime isn't tied to one method call. Anything you create with new (a List, a Person, a Library) lives on the heap.

You usually don't think about which region a value lives in. But when something surprising happens — "why did changing one variable also change another?" — the answer almost always traces back to this picture. We'll come back to it when we talk about value vs reference types.

6. Method call walkthrough

Let's trace a tiny program step by step.

Code Block
C# 13

Here is what happens in the stack while this runs:

Two things to notice:

  • Every method call gets its own stack frame, with its own copy of its parameters and local variables.
  • When the method returns, that frame is destroyed, and the caller picks up where it left off.

This is why a variable named x inside Square and a variable named x somewhere else don't interfere — they're in different frames.

7. Garbage collection: who frees memory

In C and C++, you are responsible for freeing memory you allocated. In C#, the runtime does it for you, via the garbage collector (GC).

The garbage collector periodically pauses your program briefly, walks the heap, identifies objects that no living code can still reach, and frees their memory.

You will not "feel" the garbage collector most of the time. But the fact that it exists is the reason you can write programs like this without worrying about memory:

Code Block
C# 13

8. The full lifecycle, one more time

Let's redraw the whole picture, now with the pieces named.

That is the entire journey of one C# program. Every later chapter in this course is just a closer look at some piece of this picture.

Test your understanding

QuestionSelect one

What does the Roslyn compiler produce when it compiles a C# program?

Machine code for your CPU

A Word document

An assembly (a .dll or .exe) containing Intermediate Language (IL)

A pre-rendered video of your program running

QuestionSelect one

What is the difference between the stack and the heap?

The stack is for code, the heap is for data

They are the same thing

The stack holds short-lived bookkeeping for method calls (parameters, locals, return addresses). The heap holds longer-lived objects created with new and managed by the garbage collector.

The heap is faster than the stack

QuestionSelect one

What does the garbage collector do?

Deletes unused files from your disk

Recompiles your code

Finds heap objects that no living code can still reach, and reclaims their memory so it can be reused

Slows your program down on purpose

On this page