Introduction to RTOS Part 4 - Memory Management | Digi-Key Electronics
Gestión de Memoria en RTOS
Introducción a la gestión de memoria
- La gestión de memoria es crucial al escribir código para un RTOS, ya que entender dónde se almacena cada dato ayuda a prevenir desbordamientos de pila y fugas de memoria.
Asignación estática y dinámica
- Al iniciar un programa, se asigna una sección de memoria para variables globales y estáticas, conocida como memoria estática. Esta no puede ser utilizada por otras partes del programa.
- Las variables locales dentro de una función se almacenan en la pila (stack), que opera bajo el principio LIFO (último en entrar, primero en salir). Esto facilita la gestión durante llamadas a funciones anidadas.
Crecimiento automático de la pila
- La pila puede crecer automáticamente según sea necesario, reservando espacio adicional desde la memoria libre. Variables locales y argumentos son almacenados aquí.
- Existe otra área llamada heap (montículo), que también puede crecer durante la ejecución del programa. Su disposición exacta puede variar entre arquitecturas y compiladores.
Asignación dinámica con el heap
- El heap se utiliza para asignaciones dinámicas donde el programador indica explícitamente cuánto espacio necesita mediante funciones como
malloc.
- Es importante liberar cualquier memoria asignada dinámicamente al finalizar su uso; si no se hace, puede causar fugas de memoria difíciles de rastrear.
Problemas potenciales con el heap
- Si tanto el heap como la pila crecen sin límites, pueden sobrescribirse mutuamente, lo cual genera comportamientos indefinidos.
- En FreeRTOS, cuando se crea una nueva tarea, esta recibe una parte del heap dividida entre un bloque de control (TCB) y su propia pila.
Control sobre tareas en FreeRTOS
- Al crear tareas con
xTaskCreate, especificamos cuánto heap reservar para cada tarea. No reservar suficiente espacio puede llevar a sobrescribir áreas críticas.
- FreeRTOS permite asignar memoria estática para tareas y objetos del kernel en versiones más recientes; esto es útil en aplicaciones críticas donde las fugas podrían ser catastróficas.
Estrategias para evitar fragmentación del heap
- Al realizar múltiples asignaciones y liberaciones en el heap, este podría fragmentarse rápidamente. FreeRTOS ofrece diferentes esquemas de gestión del heap para mitigar este problema.
- Heap 4 es preferido por permitir unir áreas fragmentadas del heap; mientras que Heap 3 envuelve las funciones
mallocyfreepara hacerlas seguras ante hilos.
Consideraciones finales sobre el esquema del esp32
- El esp32 tiene varios tipos diferentes de RAM lo que complica aún más su esquema específico de asignación del heap.
Manejo de Memoria en FreeRTOS
Creación y Gestión de Tareas
- Se inicia un ejemplo donde se crea una tarea que almacena números en un arreglo y luego imprime uno de esos números. Se eliminan las tareas de configuración y bucle para asegurar que solo haya una tarea en ejecución.
- Se utiliza un arreglo grande (cien elementos), lo que consume 400 bytes. La tarea tiene asignado un kilobyte de pila, pero el overhead es de aproximadamente 768 bytes.
Desbordamiento del Buffer
- Si se excede la memoria asignada a la pila, el procesador se reinicia. Esto indica que ha ocurrido un desbordamiento del buffer.
- El "stack canary" es una medida de seguridad implementada por el sistema operativo para prevenir desbordamientos; verifica valores conocidos al final de la pila.
Ajustes en el Tamaño de Pila
- Para evitar errores, se debe calcular correctamente la memoria necesaria para la tarea, considerando tanto el overhead como las variables locales. Se sugiere aumentar el tamaño de la pila a 1500 bytes.
- Utilizar
uxTaskGetStackHighWaterMarkdel API FreeRTOS permite monitorear cuántos bytes quedan disponibles en la pila.
Monitoreo del Heap
- Con
vPortGetHeapSize, se puede observar la cantidad total de memoria heap disponible antes y después de usarmalloc.
- En FreeRTOS, es recomendable usar
pvPortMallocya quemallocno es seguro para hilos. Es importante simular uso con un retraso para evitar optimizaciones del compilador.
Manejo Seguro de Memoria Dinámica
- Al intentar asignar memoria sin suficiente espacio contiguo, se genera un mensaje indicando falta de heap. Es crucial verificar si
mallocopvPortMallocretornan null.
- Debe liberarse adecuadamente la memoria dinámica utilizando funciones específicas como
vPortFree, asegurando así que no haya fugas durante las iteraciones.
Desafío Propuesto
- Se propone crear dos tareas: una escucha entradas desde el monitor serial y almacena mensajes en heap; otra imprime los mensajes recibidos y libera esa memoria.