Ejemplo de fragmentación de memoria con Arduino

En dispositivos con poca memoria RAM, como es el caso de Arduino, cuando se asigna memoria de forma dinámica puede surgir el problema de la fragmentación. Se produce cuando la memoria libre esta fragmentada en trozos tan pequeños que no se puede reservar suficiente memoria contigua libre aunque la suma total de memoria libre es mayor que la que se trata de reservar.

Veamos un ejemplo de como se produce esta fragmentación, para ello empezaremos reservando un bloque de 1000 bytes de memoria (memory1) para limitar la memoria disponible. Luego reservamos un bloque de memoria de 300 bytes (memory2) otro de un byte (memory3) y otro de 300 (memory4) de nuevo. La función de ese bloque de un único byte es evitar que al liberar los otros dos bloques estos puedan unirse en un mismo bloque. Liberamos los dos bloques de 300 bytes por lo que ahora debería haber libre un mínimo de 600 bytes libres, sin embargo si tratamos de reservar 500 bytes (memory5) y no puedo (el puntero tiene valor 0). Hay memoria libre suficiente pero esta divida en bloques más pequeños del que necesito. Con solo un byte estratégicamente colocado hemos causado un problema de fragmentación. Los bloques más pequeños (memory6) pueden reservar memoria sin problemas.

byte* memory1;
byte* memory2;
byte* memory3;
byte* memory4;
byte* memory5;
byte* memory6;

void setup() {  
  Serial.begin(9600);
  while (!Serial) {
    ; // esperamos a que el puerto este inicializado 
  }

  memory1 = (byte*) calloc (1000, sizeof(byte)); //reservamos 1000
  memory2 = (byte*) calloc (300, sizeof(byte)); //reservamos 300
  memory3 = (byte*) calloc (1, sizeof(byte)); //reservamos 1
  memory4 = (byte*) calloc (300, sizeof(byte)); //reservamos 300
  free(memory2); // liberamos 300
  free(memory4); //liberamos 300 
  memory5 = (byte*) calloc (500, sizeof(byte)); //reservamos 500
  memory6 = (byte*) calloc (300, sizeof(byte)); //reservarmos 300

  Serial.println((long)memory1);
  Serial.println((long)memory2);
  Serial.println((long)memory3);
  Serial.println((long)memory4);
  Serial.println((long)memory5);
  Serial.println((long)memory6);
}
 
void loop() {

}

Veamos un ejemplo de salida:

466
1468
1770
1774
0
1468

Se puede ver que memory5 no puede reservar memoria mientras que a memory6 se le asigna el primer bloque libre que coincide con el memory2 que acaba de ser liberado.

Este ejemplo esta pensado para una placa Arduino UNO en caso de usarlo en otra placa habrá que ajustar el tamaño del primer bloque.