memory usage "dos and don'ts"
As you have noticed yourself, this can be somewhat platform-dependent. Since you are working on a Nano, my answer will be for the AVR architecture, when compiled with gcc, the avr-libc, and the Arduino core library.
First, let me reassure you: this weird behavior you saw of the Wixel doesn't happen on this platform. Local variables get allocated mostly in CPU registers, then on the stack.
Now, the first general rule may sound obvious: think twice about what
your program really needs to remember. Also, use each time the
smallest possible data type. The C99 types int8_t
, uint16_t
and co.
are useful for this.
Another rule you will often hear on this platform: avoid dynamic
allocation, i.e. malloc()
and new
, as quite often you cannot afford
heap fragmentation. Avoid also the String
class, as it relies on
dynamic allocation. Prefer when possible static allocation, or stack
allocation for small things.
Don't forget to use const
for constants: with this qualifier the
compiler can often optimize the constants out as immediate operands. For
arrays of constants, use PROGMEM
. Yes, it's not comfortable
to use, but it can save you lots of RAM. The F()
macro for printing
constant messages is a special case of PROGMEM
.
Lastly, be very careful with recursion.
Edgar's got some great tips, and I'll reiterate one before giving a few more:
avoid dynamic memory allocation
Don't use malloc. When you're designing a system, budget out your RAM like you do your monthly budget. Make sure you're able to do everything at once.
And a couple other tips:
global statics
Make full use of the BSS block; try to block out space for as much as possible in global static
arrays. You may shudder or scoff at the idea of putting everything at a global level, but embedded is a paradigm shift, with its own set of rules.
Since you'll have so many variables at a global level, static
helps you to avoid polluting your namespace too much.
avoid fancy C++ features
In fact, try to not use C++ at all. C++ takes you "farther from the metal," with its RAII and its constructors and its implicit type conversion... It's much harder to keep a tight inventory of all of your resources when your language does so much behind the scenes. If you really want to use a certain C++ language feature, try to keep the tone of your code more like "C with bits of C++" rather than "C++ shoehorned into an embedded system." That never goes well.
Especially avoid generics/templates, which will eat up lots of your memory. Every time you use a new type with a template in your code, another copy of the template class is compiled into your program, just for that one type. Ever wonder why C++ binaries can balloon to 20, 50, even 100 MB? Templates, man. Templates.
const
This keyword should go on as many variables as it can. Keeping this habit will save on both execution time and space consumption. Learn the difference between const T* foo
, T* const foo
, and const T* const foo
.