As I'm working on a project which does a lot of dynamic memory allocation, it would indeed be quite useful to have a function to check the amount of free memory.
I tried the function Duff recommended, from the most recent SdFat library (sdfatlib20130629.zip) the SdFatUtil.cpp file
https://code.google.com/p/sdfatlib/downloads/list.
After testing this function, I am not sure if it works correctly, or does what I want. (@Duff, does it work for you?)
Initially I tried testing the function with the following, the first part is just a straight copy paste from the SdFatUtil.cpp file, after that I use the main method instead of the Arduino's setup & loop, as I compile using the makefile.
Code:
#include "WProgram.h"
#include <stdlib.h>
#ifdef __arm__
// should use uinstd.h to define sbrk but Due causes a conflict
extern "C" char* sbrk(int incr);
#else // __ARM__
extern char *__brkval;
extern char __bss_end;
#endif // __arm__
// function from the sdFat library (SdFatUtil.cpp)
// licensed under GPL v3
// Full credit goes to William Greiman.
int FreeRam() {
char top;
#ifdef __arm__
return &top - reinterpret_cast<char*>(sbrk(0));
#else // __arm__
return __brkval ? &top - __brkval : &top - &__bss_end;
#endif // __arm__
}
void* current;
extern "C" int main(void) {
Serial.begin(9600);
delay(5000);
Serial.println("Go");
while (1){
delay(10);
current = malloc(1); // allocate a byte
Serial.print("Free ram:");Serial.print(FreeRam());
Serial.print(","); Serial.println((uint32_t ) current); // print the pointer
}
}
The output of this file is the following:
Code:
Go
Free ram:8167,536866880
Free ram:8167,536866896
...
Free ram:8167,536870880
Free ram:4071,536870896
...
Free ram:4071,536874976
Free ram:-25,536874992
...
Free ram:-25,536878976
Free ram:-25,536878992
*stops printing
The idea of the output is to print the output of the FreeRam function, as well as the address of the pointer. Now the number looks a bit large, I'm not sure what causes that, however, it can be seen that the pointer increments in 16 byte steps. So possibly malloc() always allocates 16 byte chunks.
I went on to investigate what's happening, I came across
http://playground.arduino.cc/Main/CorruptArrayVariablesAndMemory#Memory_info_from_running_Arduino,
https://en.wikipedia.org/wiki/Data_segment
Which obtains information about the compiled code using 'avr-size', after some searching I found arm-none-eabi-size, which I guess is also used by the IDE to provide a memory indication
Calling the arm-none-eabi-size command on my elf file
Code:
$ arm-none-eabi-size main.elf
flash, block=0, bs=1024, auto=1
text data bss dec hex filename
48532 1628 2252 52412 ccbc main.elf
The page from the Arduino playground states in the conclusion: for an approximation at compile time; SRAM as .data+.bss ( is already used)
Subtracting the first and last pointer from the produced output we get:
536878992-536866880 = 12112
Now, adding the difference between the pointers, the bss block and the data block:
12112+1628+2252 = 15992
Which is pretty much the 16k the Teensy 3.0 has available.
Initially I thought the function perhaps only measured the stack and therefore wasn't taking my malloc() data into account, however, replacing the main method with:
Code:
extern "C" int main(void) {
Serial.begin(9600);
delay(5000);
Serial.println("Go");
Serial.print("Free ram:"); Serial.print(FreeRam()); Serial.println(" Adding a char.");
char foo = 1;
Serial.print("Free ram:"); Serial.print(FreeRam()); Serial.println(" Adding an int16.");
int16_t bar = 2;
Serial.print("Free ram:"); Serial.print(FreeRam()); Serial.println(" Adding an int32.");
int32_t baz = 3;
}
If I understand it all correctly, this places three variables onto the stack, printing the memory usage in between.
Code:
Go
Free ram:8159 Adding a char.
Free ram:8159 Adding an int16.
Free ram:8159 Adding an int32.
Where the free ram does not change at all. I'm not entirely sure what this means.
The output of the FreeRam function only changes in blocks of 8167-4071 = 4096 bytes. I think this is due to something determining how a chunk of 4096 bytes of memory is used, whether it is used for the heap or for the stack. I'm not sure about this though.
I see a workaround, somehow get the values of the .bss and .data block in the code, allocate a byte at the beginning of execution to get the location of the first byte of the heap, after which you can check how much is still free by locating another byte, subtracting them and adding the .data and .bss blocks to it. This provides the ram which is still available for allocation. However, I believe this does not take into account the size of the stack.