4.8 KiB
K05 — C++ heap bridge, heap models and HeapStats
Position
- Series: FreeRTOS C++
- Lesson: L04, card K05
- Duration: 30 minutes
- Runtime: real FreeRTOS V11.3.0
heap_4.con Hazard3/RV32I - C++ mode: freestanding C++17, no exceptions, RTTI or hosted
libstdc++ - New surface:
HeapStats,HeapWatermark, completenew/deletebridge
K03 proved one-owner RAII, while K05 now exposes the allocator policy and its metrics. It does not introduce runtime resource selection; K06 will build that on top of the explicit failure and alignment contract established here.
Outcome
After 30 minutes the student can choose among heap_1…heap_5 for a stated
memory topology/lifetime policy, enumerate all C++ allocation bridge forms,
distinguish total free bytes from largest free block, and prove that
minimum-ever free bytes retain history after current free returns to baseline.
Lesson plan — 30 minutes
| Time | Mode | Evidence |
|---|---|---|
| 0–5 | choose policy | justify heap scheme for three deployments |
| 5–9 | bridge | trace new[] -> pvPortMalloc and delete[] -> vPortFree |
| 9–14 | predict | draw A/B/C blocks and predicted stats after freeing A/C |
| 14–21 | Hazard3 | prove request < total, request > largest, failure |
| 21–26 | coalescence | free B; retry same request; inspect one free block |
| 26–30 | history/exit | baseline recovery versus minimum-ever history |
Policy table
| Scheme | Free? | Coalesce? | Key deployment constraint |
|---|---|---|---|
| heap_1 | no | n/a | monotonic startup allocation only |
| heap_2 | yes | no | holes remain separate; fragmentation grows |
| heap_3 | libc | libc | linker/compiler must provide a suitable heap |
| heap_4 | yes | yes | one FreeRTOS-owned region |
| heap_5 | yes | yes | regions defined in increasing address order before allocation |
Student choices:
- All objects allocated once at startup, never deleted:
heap_1is a valid simplest policy. - One freestanding RAM region, dynamic tasks/queues with deletion:
heap_4. - Two disjoint RAM banks that must both feed the kernel allocator:
heap_5.
heap_3 is not treated as a portable freestanding default because it delegates
storage and behavior to the compiler C library and linker heap.
Canonical experiment
baseline: [ free ........................................ ]
allocate: [ A 2K ][ B 4K ][ C 2K ][ free ............... ]
free A/C: [ free ][ B live ][ free + trailing free ...... ]
total=12256, largest=10192, blocks=2
request 10193 -> FAIL (sum is enough, no individual block is)
free B: [ one coalesced free block ..................... ]
retry 10193 -> SUCCESS
free retry -> current free returns to baseline
minimum-ever remains at the historical low
Exact values may change with alignment/header configuration. Assessment uses relations, except for the fixed requested payload sizes in the source.
Stable evidence contract
| Evidence | Required relation |
|---|---|
| C++ addresses | three distinct, aligned addresses inside ucHeap |
| bridge counters | allocations=3, deallocations=3, live=0 |
| deallocation order | A, C, B |
| fragmented stats | free blocks >=2 and total > largest |
| failed request | largest < request < total; successful allocations unchanged |
| coalesced stats | free blocks=1; largest=current=baseline |
| retry | same request succeeds inside ucHeap |
| final stats | current=baseline, minimum-ever remains below current |
Complete bridge contract
void* operator new(size_t);
void* operator new[](size_t);
void operator delete(void*) noexcept;
void operator delete[](void*) noexcept;
void operator delete(void*, size_t) noexcept;
void operator delete[](void*, size_t) noexcept;
Ordinary new is fail-fast in this course profile because exceptions are off.
The recoverable experiment uses raw pvPortMalloc and checks nullptr.
Misconceptions
- Total free bytes do not imply one payload of that size can be allocated.
- Returning to the current-free baseline does not erase the minimum-ever watermark.
heap_4limits external fragmentation by coalescing; it cannot promise absence of all fragmentation while live blocks separate holes.- A C++ bridge selects one heap domain; it does not merge five schemes.
heap_3inherits the C library/linker heap contract and is therefore not a self-contained freestanding answer.
Acceptance
- host test verifies field mapping and current/peak watermark calculations;
- ABI test finds all six allocation functions and no hosted C++ runtime;
- Hazard3 reaches all seven checkpoints and PASS;
- failure request lies strictly between largest block and total free bytes;
- retry succeeds only after B is freed and blocks coalesce;
- student chooses heap_1, heap_4 and heap_5 for the three stated scenarios and justifies each constraint.