3

I use the following code to print the currently used SRAM space:

// this function will return the number of bytes currently free in RAM
// written by David A. Mellis
// based on code by Rob Faludi http://www.faludi.com

#include "TypeDefs.h"

int availableMemory()
{
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

int printAvailableMemory(uint32 location)
{
  Serial.print(F("Available Memory at "));
  Serial.print(location);
  Serial.print(F(": "));
  Serial.println(availableMemory());
}

My main application (stripped) looks like:

...
void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(115200);
  printAvailableMemory(1);

  printAvailableMemory(2);

  test();
  printAvailableMemory(3);
}

void test()
{
  Preferences _prefs2;
  _prefs2.Set();
  printAvailableMemory(4);
}

While preference (.h) looks like:

#include "TypeDefs.h"

class Preferences
{
   private:
      uint8 _startChannel;
      uint8 _endChannel;
      uint8 _startNote;
      uint8 _endNote;
      uint8 _startCc;
      uint8 _endCc;
   ...
};

The output is:

Available memory at 1: 1065
Available memory at 2: 1065
Available memory at 4: 1065
Available memory at 3: 1065

I would expect the numbers (1065) would change, since a local variable (_prefs2) is made so at location 4 I would expect more space to be used.

Also, if I remove the _prefs2 code like below, the numbers stay the same.

void test()
{
    printAvailableMemory(4);
}

Why is the local variable not counted?

  • Local variables are allocated on the stack. – Ignacio Vazquez-Abrams Mar 18 '17 at 18:35
  • Are you actually doing something with _prefs2 other than setting it (which is what I assume .Set() does)? If not, the compiler may well have optimized it out. Check the generated assembly to see what happened. – Edgar Bonet Mar 18 '17 at 20:11
3

Why is the local variable not counted?

Let us start with the function availableMemory(), what does it do?

int availableMemory()
{
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

It returns the amount of memory between the top of stack (address of local variable v) and the heap end.

The answer lays in how the compiler works. One strategy that is used is function in-lining. This forces the functions test(), printAvailableMemory(), availableMemory(), etc. to be unfolded into loop() (which actually also gets unfolded into main()).

A common frame with the local variables is created and the variable for the top of the stack becomes one of them. You need a tougher test case to see how the stack top changes, e.g. tell the compiler not to in-line a function.

int availableMemory() __attribute__ ((noinline));

To check this generate the assembly listing for your sketch.

Cheers!

  • Thank you very much for this detailed answers. I should have known about inline compiling, I just am not used (anymore) to lower level languages (which I don't mean as offensive). Good to have such refresh about how compilers work. – Michel Keijzers Mar 18 '17 at 20:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.