Boxed vs Unboxed Memory Explorer
Run the Boxed vs Unboxed Memory Explorer MicroSim Fullscreen
You can include this MicroSim on your website using the following iframe:
1 2 | |
About This MicroSim
The previous MicroSim showed that @viper is roughly 3.5× faster than plain
MicroPython, and that the thing which changes at that rung is the value
representation. This is that change, drawn out.
Both panels compute the same thing: a + b, where a and b are floats. Press
Step forward and watch the two paths diverge.
Seven Operations Versus One
In the boxed world, a float is not a float. It is a pointer to a heap object containing a type tag, a reference count, and — eventually — the actual value.
| Step | Boxed | Unboxed |
|---|---|---|
| Follow the pointers | 2 ops | 0 |
| Check the types | 2 ops | 0 |
| Extract the values | 2 ops | 0 |
| Add and store | 1 op + allocation | 1 op |
| Total | 7 | 1 |
The counts are illustrative rather than a precise cycle count, but the ratio is the point and it is not exaggerated.
The Allocation Is the Worst Part
Notice what happens at the final step in the boxed path: adding two numbers allocates memory. The result needs a new heap object, because a boxed value cannot exist anywhere else.
Inside an FFT inner loop running thousands of butterflies, that is thousands of allocations. Each one is slow on its own, and collectively they eventually trigger garbage collection — which pauses your program at a moment you do not control. For a real-time deadline, an unpredictable pause is worse than a predictable cost.
That is why an unboxed inner loop is not merely faster on average. It is faster and it does not have a tail.
What Unboxing Costs You
The unboxed slot holds 3F800000 — four raw bytes. There is no type tag, so
nothing checks that those bytes are a float. If you annotated the variable wrong,
the ADD happily operates on nonsense and returns nonsense.
The type check you removed was doing something. Removing it is the trade.
How to Use
- Press Step forward four times and watch the tallies diverge.
- At each step, read which fields lit up in the boxed diagram and note that nothing lit up in the unboxed one.
- Reach the final step. Note that the boxed path allocates and the unboxed path does not.
- Ask: in a loop running 2,304 butterflies, how many allocations does the boxed version make?
- Uncheck Show operation tally and re-read the diagrams. The structural difference is visible even without the counter.
Lesson Plan
Grade Level
Undergraduate (college junior/senior)
Duration
10-12 minutes
Prerequisites
- Pointers and heap allocation
- Variables occupy memory
Learning Objective
Students will be able to explain why arithmetic on a boxed value requires more memory accesses than the same arithmetic unboxed, by comparing their memory layouts step by step.
Activities
- Count together (4 min): Students step both paths and record the tally at each stage.
- Find the allocation (4 min): Students identify the step that allocates and explain why it matters more than the reads.
- Name the cost (4 min): Students state what safety property unboxing gives up and construct an example where it bites.
Assessment
Ask: "An FFT butterfly does one complex multiply and two complex adds. In boxed MicroPython, roughly how many heap allocations is that per butterfly, and what happens after a few thousand of them?"
Related Resources
References
- Boxing (computer programming) — the representation shown in the top panel.
- MicroPython maximising speed — the official guidance on avoiding allocation in inner loops.
- Garbage collection — why unpredictable pauses matter for real-time code.