All jobs / Embedded / hardware
Memory interview questions
Memory questions a Embedded / hardware can be asked, from first job to senior. Open one to see the strongest answer and why it works.
Why are people cautious about malloc on a small MCU?
The strongest answer: Fragmentation, no-fail stories, and ISR rules — I prefer static or a pool I can size, I do not malloc in an interrupt
Why it works: Exactly. Size what you can see. Heap in an ISR or a fault is how you lose the chip twice.
- Prefer static or a sized pool.
- No malloc in ISR or fault.
- Heap can fragment and fail.
- Do not copy desktop habits blindly.
A function works until you add a log line, then you hard-fault. Suspect?
The strongest answer: Stack overflow or a smashed frame — I look at stack size, big locals, and recursion, not “logs are cursed”
Why it works: Exactly. A log line is more stack. Curses and disabled faults are how you ship a bomb.
- Suspect stack when a tiny add faults.
- Check size, locals, recursion.
- Do not disable the fault handler.
- Do not pad with more stack use.
The image will not fit. What file do you open?
The strongest answer: The map/listing — who ate flash and RAM — not a random delete of “debug” until it links
Why it works: Exactly. The map is the diet. -O0 usually grows. Vector tables are not snacks.
- Read the map file.
- See who ate RAM/flash.
- Do not delete the vectors.
- -O0 is not a shrink.
Where would you keep a setting the user changes, and why is that different from where the code lives?
The strongest answer: Code lives in flash, which is erased a whole sector at a time, so rewriting one setting there means erasing a block; EEPROM — or an emulation of it in flash — is built for small byte-sized updates
Why it works: Right — erase granularity is the whole point, and it also explains why many MCUs emulate EEPROM rather than having it.
- Erase granularity decides where data lives.
- Flash erases by sector, not by byte.
- EEPROM, or emulation, for small updates.
- Never assume a graceful shutdown.
A write to an address “does nothing.” First read?
The strongest answer: The memory map and MPU/alignment — is it flash, reserved, cached, or the wrong alias — not a bigger hammer of writes
Why it works: Exactly. Maps lie less than hope. Hammers and deleted MPUs are how you brick a day.
- Open the memory map.
- Check alias, cache, MPU, alignment.
- Do not hammer all-ones.
- Do not delete the MPU as a first fix.
How do you know a task stack is enough before the field?
The strongest answer: Watermarks or a deliberate fill, plus the worst call chain I can name — I do not pick 512 because it is a nice number
Why it works: Exactly. Measure the high-water. Shared stacks and disabled checks are how you corrupt late.
- Measure high-water.
- Name the worst chain.
- Do not pick a cute 512.
- Do not share task stacks to save RAM.
Why is writing flash during a shaky rail a special fear?
The strongest answer: A brownout mid-program can brick or corrupt the only copy — I want BOD, a stable rail, and a recovery image
Why it works: Exactly. Flash needs a polite rail. Faster-and-no-BOD is how you brick at the worst time.
- BOD + stable rail + recovery image.
- Flash is not voltage-immune.
- Do not skip BOD to go faster.
- Do not program flash as the motor kicks.
You log every state change to the same flash page. Risk?
The strongest answer: Wear and a brick on a busy unit — I wear-level, buffer, or use a part meant for logs
Why it works: Exactly. Endurance is finite. Per-byte erase and ISR logs are how you die young.
- Respect flash endurance.
- Wear-level or buffer logs.
- Do not erase per byte.
- Do not log from a hot ISR.
A global initialised to a non-zero value reads as zero in the first function main calls, but only in the release build.
Which part of start-up do you go and read?
The strongest answer: The code that runs before main: it copies .data initial values from flash into RAM and zeroes .bss. If that copy is skipped, or the linker script’s addresses are wrong, initialised globals read as zero
Why it works: Exactly — and that is also why a zero-initialised global costs no flash while a non-zero one costs flash and RAM.
- Start-up builds RAM before main runs.
- .data is copied from flash.
- .bss is zeroed.
- The linker script defines both regions.
After weeks up, allocs fail though “plenty” of free heap. What is it?
The strongest answer: Fragmentation — I move to pools or static, I do not print free bytes and call it healthy
Why it works: Exactly. Free ≠ usable. Nightly reboots and bigger heaps are souvenirs.
- Suspect fragmentation.
- Prefer pools/static.
- Free bytes ≠ healthy.
- Do not malloc in the fault path.
Why do people pay for dual-bank flash on a field device?
The strongest answer: So an update can fail and still boot the last good bank — I do not treat a second bank as “more log space” first
Why it works: Exactly. A way back. Logs, skipped sigs, and dual-erase are how you buy the part and waste it.
- Dual-bank is rollback.
- Not extra log space first.
- Not a reason to skip signatures.
- Do not erase both at once.
RAM is gone and every team wants a buffer. What do you standardise?
The strongest answer: A budget with owners and a no-hidden-heap rule — I do not standardise every naming taste
Why it works: Exactly. Owned bytes. Merge-races and hidden heaps are how you die in the field.
- Owned RAM budget.
- No hidden heap.
- Not first-merge-wins.
- Do not ritual-buy a bigger MCU.