Odd memory allocation behaviour

I recently raised a topic on Serial.println statements ‘disappearing’. The best advice I got back on this was that it was most likely caused by running out of RAM.

I’m now quite convinced that the odd behaviour I was witnessing with the ‘missing’ println statements is due to memory issues. However, doing a bit more experimenting in this area has raised more questions than it has provided answers, so I’m starting this new topic to look at memory allocation.

I’ve written the attached program to try and see how the program behaves as the memory is gradually consumed. The results are confusing and don’t make a whole lot of sense to me. Perhaps someone can shed some light here.

Here’s the test application. It’s designed to leak a few bytes and then print out the amount of remaining memory on every iteration of loop().

/*

  • Example program to test memory limits
    */

char abuff[150];
void *myP;

// this function will return the number of bytes currently free in RAM
int memoryTest() {
int byteCounter = 0; // initialize a counter
byte *byteArray; // create a pointer to a byte array

// use the malloc function to repeatedly attempt allocating a certain number of bytes to memory
while ( (byteArray = (byte*) malloc (byteCounter * sizeof(byte))) != NULL ) {
byteCounter++; // if allocation was successful, then up the count for the next try
free(byteArray); // free memory after allocating it
}

free(byteArray); // also free memory after the function finishes
return byteCounter; // send back the highest number of bytes successfully allocated
}

void displayMemoryLeft() {
int iAvail;
Serial.print(“Memory test results: “);
iAvail = memoryTest();
Serial.print(iAvail,DEC);
Serial.println(” bytes free”);
}

void setup()
{
Serial.begin(9600);
}

void loop()
{
Serial.println(“Top of loop”);
displayMemoryLeft();
myP = malloc(20);
if (myP == NULL) Serial.println(“Allocation did not work”);

Serial.println(“Waiting 2 seconds\n”);
delay(2000);
}

This compiles with the following summary.

Binary sketch size: 2778 bytes (of a 14336 byte maximum)

When I run it, I get the following output.

Top of loop
Memory test results: 318 bytes free
Waiting 2 seconds

Top of loop
Memory test results: 296 bytes free
Waiting 2 seconds

Top of loop
Memory test results: 274 bytes free
Waiting 2 seconds

Top of loop
Memory test results: 253 bytes free
Waiting 2 seconds

Top of loop
Memory test results: 253 bytes free
Waiting 2 seconds

Top of loop
Memory test results: 253 bytes free
Waiting 2 seconds

So, each 20 byte malloc results in 22 bytes being removed from memory, but why does the memory not fall below 253 bytes? This is unexpected behaviour.
If I then remove the abuff variable, the program behaves very differently, commencing with an available memory size of 638 bytes and dropping gradually down to 89 bytes.

Can anyone help me to explain this behaviour? Also, if I didn’t have Serial.println statements in my code, how would I ever know that this odd behaviour was occurring? My point here is that an embedded program is unlikely to have println statements in its final form, so determining that the memory limits are being hit, and odd behaviour is likely to occur, seems to me to be very difficult to predict.

Hello.

Very interesting results from some very systematic testing. Rather than repeat what I've already said on this topic elsewhere, I'll just point you to my previous post on this topic in case you might find the information there helpful:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210982938/1#1

  • Ben

Also the memoryTest() function(s) aren't very precise. They actually measure the largest single block of memory you can allocate, which is often not the same as the total amount of free memory (since the free memory may be split up into pieces).

Thanks for the replies. They have helped clarify for me how the memory allocation works and why I am getting this behaviour. I know its been said before, but this really is like going back to my early days of programming in the 70's with a ZX81. I'd pretty much forgotten how constrained that programming environment was, but these recent experiences with the Atmega168 has brought it all back once again!!