I have a question regarding memory allocation.
I know that using heap on Arduino is a discouraged practice, but I have to do because I must instantiate objects from a own-created library.
But here I'll start with a simpler example. I want to reserve memory for a single integer and then release it.
I implemented the new and delete C++ operators within the CPlusPlusFixes library, and a method to show how much RAM is available within the FreeMemory library instead.
The strange thing is that when using new/delete the memory is correctly de-allocated, while when using malloc/free it is not.
Output with new/delete:
Free available memory (bytes): 7499
Free available memory (bytes): 7495
Free available memory (bytes): 7499
Output with malloc/free:
Free available memory (bytes): 7499
Free available memory (bytes): 7495
Free available memory (bytes): 7495
Here it is the code of the FreeMemory library (based on the example from the Arduino Playground).
FreeMemory.h
/*
* Count the remaining free bytes in RAM.
*/
#ifndef FREE_MEMORY_H
#define FREE_MEMORY_H
#ifdef __cplusplus
extern "C" {
#endif
int getFreeMemory (void);
int checkMem (void);
#ifdef __cplusplus
}
#endif // ifdef __cplusplus
#endif // ifndef FREE_MEMORY_H
FreeMemory.cpp
#include "WProgram.h"
#include "FreeMemory.h"
//extern unsigned int __data_start;
//extern unsigned int __data_end;
//extern unsigned int __bss_start;
//extern unsigned int __heap_start;
// top of the static variable memory
extern unsigned int __bss_end;
// top of the heap (0 if malloc() is not used)
extern void *__brkval;
int getFreeMemory (void)
{
int free_memory;
if ((int) __brkval == 0) {
free_memory = ((int) &free_memory) - ((int) &__bss_end);
}
else { // malloc is used
free_memory = ((int) &free_memory) - ((int) __brkval);
}
return free_memory;
}
int checkMem (void)
{
byte *heapptr = 0;
byte *stackptr = 0;
// retrieve the value of the heap pointer
stackptr = (byte *) malloc(4);
heapptr = stackptr;
free(stackptr);
// retrieve the value of the stack pointer
stackptr = (byte *) SP;
return (stackptr - heapptr);
}
When you use new and delete, fix28135_malloc_bug() gets called after the delete calls free(). When you use malloc() and free() directly, it does not. So I guess you are seeing the bug that fix28135_malloc_bug() is intended to fix.
Using new or malloc() is OK in setup() code, but I advise against using delete or free() anywhere. If you really want to allocate and free objects, consider maintaining your own freelist of same-size objects instead.
The main danger is that your free memory will fragment and a malloc or new call will fail when there is sufficient total free memory but it is divided into chunks that are all too small to satisfy the current request. The system runs until this happens, then crashes. In PC based programs running Windows or Linux, the problem is typically masked by virtual memory, however I have known applications run out of address space (typically 2Gb max for 32-bit programs) due to memory fragmentation.
If your malloc/free or new/delete calls are always for exactly the same size object, fragmentation should not occur and you may get away with it.
I already know about the memory fragmentation problem on embedded systems.
My malloc/free are almost always for the same size objects, except a few special cases (5% of the total, more or less) where a different sized object is created.
Thanks again for your suggestions and for the useful link.
Unfortunately I don't have any examples of custom freelist implementation to hand. The principle is:
include a link field in your object so that you can chain free objects together (normally you will re-use one of the existing fields)
declare a freelist root pointer for each class as a static member of the class
when you want to allocate a new object of the class, look in the freelist first, if it is not empty then take an object off that and use it. Only allocate a new object from the heap if the freelist is not empty.
when you want to free an object, just put it on the freelist.
You can overload placement new and delete operators for the class in order to make this transparent, so that this all happens under the covers when you use new and delete as normal.
The disadvantage is that memory in the freelist for one class cannot be used for allocating objects of a different class. The advantage is that fragmentation is avoided.