Free memory questions

Hi,

I'm trying to save memory (RAM or data memory, not program memory) on a Mega2560, and I'm testing out some code I've found on this forum for displaying how much free memory is available. Firstly, here's the code I'm using....
.h file...

 // memoryFree header
#ifndef	MEMORY_FREE_H
#define MEMORY_FREE_H

#include "WProgram.h"     // needed for 'Serial'


#ifdef __cplusplus
extern "C" {
#endif

int freeMem();
int freeRam();
//void checkMem();

#ifdef  __cplusplus
}
#endif

#endif

.cpp file.....

#include "WProgram.h"  
#include "MemoryFree.h"

extern unsigned int __data_start;
extern unsigned int __data_end;
extern unsigned int __bss_start;
extern unsigned int __bss_end;
extern unsigned int __heap_start;
extern void *__brkval;


int freeMem()
{
  int free_memory;

  if((int)__brkval == 0)
     free_memory = ((int)&free_memory) - ((int)&__bss_end);
  else
    free_memory = ((int)&free_memory) - ((int)__brkval);

  return free_memory;
}


int freeRam() 
{
  //int size = 1024; // Use 1034 with ATmega328
  //int size = 2048;  // Use 2048 with ATmega328 (Duemilanove)
  int size = 8192;  // Use 8192 with a Mega2560
  byte *buf;

  while ((buf = (byte *) malloc(--size)) == NULL);

  free(buf);

  return size;
}

Just to try to get some understanding of what's going on I've written some simple tests...

  Serial.print("Step 0. freeMem=<");Serial.print( freeMem() );Serial.print("> (bytes), freeRam=<");Serial.print( freeRam() );Serial.println("> (bytes)");
  char stringA[100+1];
  stringA[0]=0;
  for (int z=0;z<10;z++)
  {
    Serial.print("z=<");Serial.print(z);Serial.print(">, strlen()=<");Serial.print(strlen(stringA));Serial.print(">. freeMem=<");Serial.print( freeMem() );Serial.print("> (bytes), freeRam=<");Serial.print( freeRam() );Serial.println(">");
    strcat(stringA,"1234567890");
  }
  
  Serial.print("Step 1. freeMem=<");Serial.print( freeMem() );Serial.print("> (bytes), freeRam=<");Serial.print( freeRam() );Serial.println("> (bytes)");
  char stringB[100+1];
  stringB[0]=0;
  for (int z=0;z<10;z++)
  {
    Serial.print("z=<");Serial.print(z);Serial.print(">, strlen()=<");Serial.print(strlen(stringB));Serial.print(">. freeMem=<");Serial.print( freeMem() );Serial.print("> (bytes), freeRam=<");Serial.print( freeRam() );Serial.println(">");
    strcat(stringB,"1234567890");
  }

  Serial.print("Step 2. freeMem=<");Serial.print( freeMem() );Serial.print("> (bytes), freeRam=<");Serial.print( freeRam() );Serial.println("> (bytes)");
  char stringC[100+1];
  stringC[0]=0;
  for (int z=0;z<10;z++)
  {
    Serial.print("z=<");Serial.print(z);Serial.print(">, strlen()=<");Serial.print(strlen(stringC));Serial.print(">. freeMem=<");Serial.print( freeMem() );Serial.print("> (bytes), freeRam=<");Serial.print( freeRam() );Serial.println(">");
    strcat(stringC,"1234567890");
  }

Now, here’s the issue. I’m expecting that each time I add a new string and then start increasing the length the amount of available memory will go down? But it doesn’t , here’s the results…

######################################################
Test 1......
######################################################
Step 0. freeMem=<5322> (bytes), freeRam=<5284> (bytes)
z=<0>, strlen()=<0>. freeMem=<36> (bytes), freeRam=<5284>
z=<1>, strlen()=<10>. freeMem=<36> (bytes), freeRam=<5284>
z=<2>, strlen()=<20>. freeMem=<36> (bytes), freeRam=<5284>
z=<3>, strlen()=<30>. freeMem=<36> (bytes), freeRam=<5284>
z=<4>, strlen()=<40>. freeMem=<36> (bytes), freeRam=<5284>
z=<5>, strlen()=<50>. freeMem=<36> (bytes), freeRam=<5284>
z=<6>, strlen()=<60>. freeMem=<36> (bytes), freeRam=<5284>
z=<7>, strlen()=<70>. freeMem=<36> (bytes), freeRam=<5284>
z=<8>, strlen()=<80>. freeMem=<36> (bytes), freeRam=<5284>
z=<9>, strlen()=<90>. freeMem=<36> (bytes), freeRam=<5284>
Step 1. freeMem=<36> (bytes), freeRam=<5284> (bytes)
z=<0>, strlen()=<0>. freeMem=<36> (bytes), freeRam=<5284>
z=<1>, strlen()=<10>. freeMem=<36> (bytes), freeRam=<5284>
z=<2>, strlen()=<20>. freeMem=<36> (bytes), freeRam=<5284>
z=<3>, strlen()=<30>. freeMem=<36> (bytes), freeRam=<5284>
z=<4>, strlen()=<40>. freeMem=<36> (bytes), freeRam=<5284>
z=<5>, strlen()=<50>. freeMem=<36> (bytes), freeRam=<5284>
z=<6>, strlen()=<60>. freeMem=<36> (bytes), freeRam=<5284>
z=<7>, strlen()=<70>. freeMem=<36> (bytes), freeRam=<5284>
z=<8>, strlen()=<80>. freeMem=<36> (bytes), freeRam=<5284>
z=<9>, strlen()=<90>. freeMem=<36> (bytes), freeRam=<5284>
Step 2. freeMem=<36> (bytes), freeRam=<5284> (bytes)
z=<0>, strlen()=<0>. freeMem=<36> (bytes), freeRam=<5284>
z=<1>, strlen()=<10>. freeMem=<36> (bytes), freeRam=<5284>
z=<2>, strlen()=<20>. freeMem=<36> (bytes), freeRam=<5284>
z=<3>, strlen()=<30>. freeMem=<36> (bytes), freeRam=<5284>
z=<4>, strlen()=<40>. freeMem=<36> (bytes), freeRam=<5284>
z=<5>, strlen()=<50>. freeMem=<36> (bytes), freeRam=<5284>
z=<6>, strlen()=<60>. freeMem=<36> (bytes), freeRam=<5284>
z=<7>, strlen()=<70>. freeMem=<36> (bytes), freeRam=<5284>
z=<8>, strlen()=<80>. freeMem=<36> (bytes), freeRam=<5284>
z=<9>, strlen()=<90>. freeMem=<36> (bytes), freeRam=<5284>
freeMem=<36> (bytes), freeRam=<5284> (bytes)

There are a number of issues with this.
Firstly, both functions are displaying totally different values
Secondly, both functions are displaying more-or-less unchanging values.

I guess either there’s something wrong with my code (very possible) or there’s something wrong in my understand of what I should be seeing.

Any suggestions?

Thanks

Mike

I guess either there’s something wrong with my code (very possible) or there’s something wrong in my understand of what I should be seeing.

The location in the source code where the array is defined has no impact on the amount of space used when the code runs. The compiler sees all the array declarations, and allocates space for them, at compile time, not at run-time.

Putting your data in the array does not change the size of the array, so the amount of memory being used does not change.

Any suggestions?

Never stop learning.

The location in the source code where the array is defined has no impact on the amount of space used when the code runs. The compiler sees all the array declarations, and allocates space for them, at compile time, not at run-time.

Only true for static/global declarations. The OP has declared his arrays on the stack which is allocated at run time on entry to the containing control block and de-allocated upon leaving. However the quantity of memory he's pushed on to the stack is bounded by the fixed array size and does not change during the tests. To see a change while in a loop he'll need to write a recursive function (grows the stack) or allocate heap memory (grows the heap).

Ok, a couple of good points there, so what you’re saying is that if I declare an array of size [100] then 100 bytes will be allocated to it (and hence un-available to anything else) even if only a few characters of the string are used?

I assume that memory is only allocated when that particular array/object is within scope? So in my example since all of the string are within scope all of the time the amount of free memory remains the same?

Finally, Any idea why the two functions give such different values?

thanks

Only true for static/global declarations.

I was thinking in terms of the order of the print statements and the array declarations. The array is not allocated after the print occurs. I was not clear on that, but that was what I was trying to convey.

Thanks, I now know more than I did, but I’m still puzzled by what I’m seeing. I’ve modified my test sketch, and again the results aren’t what I expected.

Firstly, I’ve put each of my tests in it’s own function, I would expect to see the memory available change from as each of the string arrays go in and out of scope?
Secondly, When I call ‘free()’ I expect to see the amount of free space increase by the number of bytes in the array. Why isn’t this happening?
Thirdly, if I change the sketch and declare a couple more 100 byte arrays then I would expect free space to drop. It doesn’t. Why not?

Here’s the sketch.

#include <MemoryFree.h>                // Memory library - used to check how much free space is available

char string1[100+1];
char string2[100+1];

void setup()
{
  Serial.begin(115200);//Communication speed for the display
  Serial.println("######################################################");
  Serial.println("Starting......");
  Serial.println("######################################################");

  string1[0]=0;
  string2[0]=0;


  Serial.print("Before calling test 1. freeMem=<");Serial.print( freeMem() );Serial.print("> (bytes), freeRam=<");Serial.print( freeRam() );Serial.println(">");
  test1();
  Serial.print("After calling test 1. freeMem=<");Serial.print( freeMem() );Serial.print("> (bytes), freeRam=<");Serial.print( freeRam() );Serial.println(">");

  Serial.print("Before calling test 2. freeMem=<");Serial.print( freeMem() );Serial.print("> (bytes), freeRam=<");Serial.print( freeRam() );Serial.println(">");
  test2();
  Serial.print("After calling test 2. freeMem=<");Serial.print( freeMem() );Serial.print("> (bytes), freeRam=<");Serial.print( freeRam() );Serial.println(">");

  Serial.print("freeMem=<");Serial.print( freeMem() );Serial.print("> (bytes), freeRam=<");Serial.print( freeRam() );Serial.println("> (bytes)");
}

void loop()
{
  for (int x=0; x<30000 ;x++)
  {
    Serial.print(".");
    delay(3000);
  }
}

void test1()
{
  Serial.println("######################################################");
  Serial.println("Test 1......");
  Serial.println("######################################################");
  
  Serial.print("Step 0. freeMem=<");Serial.print( freeMem() );Serial.print("> (bytes), freeRam=<");Serial.print( freeRam() );Serial.println("> (bytes)");
  char stringA[100+1];
  stringA[0]=0;
  for (int z=0;z<9;z++)
  {
    Serial.print("z=<");Serial.print(z);Serial.print(">, sizeof=<");Serial.print(sizeof(stringA));Serial.print(">, strlen=<");Serial.print(strlen(stringA));Serial.print(">. freeMem=<");Serial.print( freeMem() );Serial.print(">, freeRam=<");Serial.print( freeRam() );Serial.println(">");
    strcat(stringA,"1234567890");
  }
  
  Serial.print("About to free 100 bytes. freeMem=<");Serial.print( freeMem() );Serial.print("> (bytes), freeRam=<");Serial.print( freeRam() );Serial.println(">");
  free(stringA);
  Serial.print("finished freeing 100 bytes. freeMem=<");Serial.print( freeMem() );Serial.print("> (bytes), freeRam=<");Serial.print( freeRam() );Serial.println(">");
}

void test2()
{
  Serial.println("######################################################");
  Serial.println("Test 2......");
  Serial.println("######################################################");
  
  Serial.print("Step 0. freeMem=<");Serial.print( freeMem() );Serial.print("> (bytes), freeRam=<");Serial.print( freeRam() );Serial.println("> (bytes)");
  char stringB[50+1];
  stringB[0]=0;
  for (int z=0;z<4;z++)
  {
    Serial.print("z=<");Serial.print(z);Serial.print(">, sizeof=<");Serial.print(sizeof(stringB));Serial.print(">, strlen=<");Serial.print(strlen(stringB));Serial.print(">. freeMem=<");Serial.print( freeMem() );Serial.print(">, freeRam=<");Serial.print( freeRam() );Serial.println(">");
    strcat(stringB,"1234567890");
  }
  
  Serial.print("About to free 50 bytes. freeMem=<");Serial.print( freeMem() );Serial.print("> (bytes), freeRam=<");Serial.print( freeRam() );Serial.println(">");
  free(stringB);
  Serial.print("finished freeing 50 bytes. freeMem=<");Serial.print( freeMem() );Serial.print("> (bytes), freeRam=<");Serial.print( freeRam() );Serial.println(">");
}

And here’s the results

#################################
Starting......
######################################################
Before calling test 1. freeMem=<6832> (bytes), freeRam=<6794>
######################################################
Test 1......
######################################################
Step 0. freeMem=<-74> (bytes), freeRam=<8191> (bytes)
z=<0>, sizeof=<101>, strlen=<0>. freeMem=<-8267>, freeRam=<8191>
z=<1>, sizeof=<101>, strlen=<10>. freeMem=<-8267>, freeRam=<8191>
z=<2>, sizeof=<101>, strlen=<20>. freeMem=<-8267>, freeRam=<8191>
z=<3>, sizeof=<101>, strlen=<30>. freeMem=<-8267>, freeRam=<8191>
z=<4>, sizeof=<101>, strlen=<40>. freeMem=<-8267>, freeRam=<8191>
z=<5>, sizeof=<101>, strlen=<50>. freeMem=<-8267>, freeRam=<8191>
z=<6>, sizeof=<101>, strlen=<60>. freeMem=<-8267>, freeRam=<8191>
z=<7>, sizeof=<101>, strlen=<70>. freeMem=<-8267>, freeRam=<8191>
z=<8>, sizeof=<101>, strlen=<79>. freeMem=<-8267>, freeRam=<8191>
About to free 100 bytes. freeMem=<-8267> (bytes), freeRam=<8191>
finished freeing 100 bytes. freeMem=<-8267> (bytes), freeRam=<8191>
After calling test 1. freeMem=<-8157> (bytes), freeRam=<8191>
Before calling test 2. freeMem=<-8157> (bytes), freeRam=<8191>
######################################################
Test 2......
######################################################
Step 0. freeMem=<-8217> (bytes), freeRam=<8191> (bytes)
z=<0>, sizeof=<51>, strlen=<0>. freeMem=<-8217>, freeRam=<8191>
z=<1>, sizeof=<51>, strlen=<10>. freeMem=<-8217>, freeRam=<8191>
z=<2>, sizeof=<51>, strlen=<20>. freeMem=<-8217>, freeRam=<8191>
z=<3>, sizeof=<51>, strlen=<30>. freeMem=<-8217>, freeRam=<8191>
About to free 50 bytes. freeMem=<-8267> (bytes), freeRam=<8191>
finished freeing 50 bytes. freeMem=<-8267> (bytes), freeRam=<8191>
After calling test 2. freeMem=<-8157> (bytes), freeRam=<8191>

I think the memory functions I’m using should be ok, they’re referenced in several places on this forum (actually, that’s no guarantee!). So either my sketch or my understanding must be faulty.

I’ve just noticed that the only time the two memory functions return plausible results (and the only time they almost agree) is the first time they’re called. Is this significant?

All help appreciated.

Mike

Secondly, When I call ‘free()’ I expect to see the amount of free space increase by the number of bytes in the array. Why isn’t this happening?

You are not dynamically allocating space in the functions, so the pointer you are passing to free is not pointing to space that can be freed. Doing that is really not a good idea.

As you can see from the results, free() is smart enough to do nothing, but one should not rely on that being the case. Only pass to free pointers that have been returned by malloc.

Firstly, I’ve put each of my tests in it’s own function, I would expect to see the memory available change from as each of the string arrays go in and out of scope?

The amount of memory available before and after a function call should be exactly the same, unless that function dynamically allocated memory (using malloc or new) and failed to release it (using free or delete, as appropriate).

Within each function, you are not changing the amount of memory allocated. Filling an already allocated array with your data, or leaving whatever was in that memory location there, does not change how much memory is in use.

Change the functions to dynamically allocate space. Then, you should see the behavior you are expecting.

Thirdly, if I change the sketch and declare a couple more 100 byte arrays then I would expect free space to drop. It doesn’t. Why not?

I think this says something about the way that those functions work. Or don't work. I'm not familiar with that library, so I won't comment on what those functions are actually measuring.

Thanks Paul,

This is radically changing my perception of how memory is handled in an arduino. I though that memory was dynamically allocated and de-allocated as objects move in and out of scope.
I guess this means that if I build a large project full of librarys and classes then ALL memory gets allocated up front no-matter no matter now deeply burried a particular object is?
Also, I guess this means that if I include some obscure little function that only ever gets called once it will still be using up it's memory allocation for the entire duration the sketch is running, rather than the brief nanoseconds when it's actually being used?
Finally, assuming I never use malloc() and free() does that mean that the amount of free memory available will remain constant at all points in the sketch?

Kind Regards

Mike

The examples you've shown so far are all basic C stuff, with static sized array. When you get to libraries and classes, dynamic allocation and de-allocation come into play. When that happens, the amount of memory available WILL change as the program executes.

It actually does with the code you have posted so far, but the change is very small. Before a function is called, there is some data on the stack. For the function call, more data is pushed onto the stack. Free memory goes down as stack size goes up.

When the function completes, the stuff pushed onto the stack is popped off, and more memory becomes available.

You'd see a bigger change if you created a function with 50 float arguments. All 50 floats are pushed onto the stack during the function call, and popped when the function ends.

Finally, assuming I never use malloc() and free() does that mean that the amount of free memory available will remain constant at all points in the sketch?

Except as required for stack space, yes.