5 votos

¿Reasignar desperdiciando mucho espacio en mi MCU?

Estoy escribiendo un simple programador de tareas y el uso de asignación dinámica de memoria en mi cc430F5137. Estoy de acuerdo en que no es una buena práctica, pero por el momento vamos a suponer que es mi requisito de aplicación para utilizar la asignación de memoria dinámica.

En mi archivo OS.c

Tengo dos estructuras,

typedef struct
{
    task_t task;
    uint8_t next;
    uint8_t prev;
    uint8_t priority;

} info_t;

typedef struct
{
    task_t task;
    uint8_t index;
} index_t;

tamaño de info_t es de 8 bytes y el tamaño de index_t es de 6 bytes.

También hago

index_t* m_index;
info_t* m_info;

Luego tengo la función inicializar en la que hago

m_info = NULL;
m_index = NULL;

Ahora tengo una función registerTask(& task) que toma la dirección de la función a programar. En esta función hago

m_info = realloc(m_info,(num_registered_tasks + 1) * sizeof(*m_info));

y luego establecer los valores de .priority, next,task y prev.

Entonces lo hago

m_index = realloc(m_index,(num_registered_tasks + 1) * sizeof(*m_index));

a y hacer num_registered_tasks++;

Mi pregunta es que cómo es realloc() comportarse a este respecto.

Supongamos que mi espacio de memoria, Primera tarea está registrada, por lo que tendrá los primeros 8 bytes para m_info[0] y los siguientes 6 bytes para m_index[0] . Ahora, cuando mi segunda tarea llame a esta función, ¿qué ocurrirá? Lo que estoy suponiendo es que para m_info primero buscará 16 bytes de datos continuos y sólo los encontrará después de los primeros 14 bytes, cambiará la dirección de m_info[0] y copiar el contenido y luego añadir m_info[1] . Y cuando m_index sólo encontrará 12 bytes después de estos (14 + 16) bytes y colocará m_index[0] y m_index[1] aquí.

Si esto es cierto, ¿entonces todo mi espacio anterior se está desperdiciando?

Si me equivoco, ¿cómo funcionará esta función?

¿Cómo puedo aprovechar también el espacio anterior?

Necesito index_t struct para implementar algún tipo de algoritmo de búsqueda por lo que es necesario también

31voto

Neil Foley Puntos 1313

Utilizar la asignación dinámica de memoria en un MCU de 16 bits con 4kb de RAM es una ingeniería muy pobre.

No tanto por los problemas habituales de fugas de memoria. No tanto por la fragmentación de la memoria heap. Ni siquiera por la sobrecarga de tiempo de ejecución bastante pronunciada necesaria para las rutinas de asignación. Sino porque es completamente inútil y no tiene sentido.

Usted tiene algunos requisitos del mundo real que indican lo que su programa debe hacer, y sobre la base de estos su programa tendrá que utilizar exactamente x bytes de RAM para manejar el peor de los casos . No necesitarás menos, no necesitarás más, necesitarás esa cantidad exacta de RAM, que se puede determinar en tiempo de compilación.

No tiene sentido guardar parte de los 4kb, dejándolos sin usar. ¿Quién va a utilizarlos? Del mismo modo, no tiene sentido asignar más memoria de la necesaria para el peor de los casos. Simplemente asigna estáticamente tanta memoria como sea necesaria, punto.

Además, en el peor de los casos, con un uso máximo de la pila, te encuentras en lo más profundo de una pila de llamadas y todas las interrupciones activadas se han disparado. Este peor escenario puede calcularse en tiempo de compilación o medirse en tiempo de ejecución. Una buena práctica es asignar más RAM de la necesaria para el peor de los casos, para evitar desbordamientos de la pila (la pila es en realidad un área de memoria dinámica también). O mejor dicho: utilice cada byte de RAM que no utilice su programa para la pila.

Si tu aplicación necesita exactamente 3kb de RAM, entonces deberías usar el 1kb restante para la pila.

La asignación dinámica/el heap del ordenador está pensado para ser utilizado en aplicaciones alojadas como Windows o Linux, donde cada proceso tiene una cantidad fija de RAM, y además puede utilizar la memoria heap para usar tanta RAM como haya en el hardware. Sólo tiene sentido utilizar la asignación dinámica en sistemas tan complejos y multiproceso, con grandes cantidades de RAM disponibles.

En un programa MCU, ya sea bare metal o basado en RTOS, tienes que darte cuenta de que las implementaciones de heap funcionan así: reserva una cantidad fija, x kb de RAM para el heap. Cuando usas la asignación dinámica, te dan un trozo de esta cantidad fija de memoria. Entonces, ¿por qué no simplemente tomar esos x kb que usarías para asignar el heap y en su lugar usarlos para almacenar tus variables?


He ampliado esto con una explicación más detallada y más posibles problemas, aquí:
¿Por qué no utilizar la asignación dinámica de memoria en los sistemas embebidos?

10voto

AnonJr Puntos 111

Esto se denomina fragmentación de la memoria.

Existen todo tipo de algoritmos sofisticados para solucionarlo, pero la sobrecarga de contabilidad los hace inadecuados para una MCU pequeña.

En su lugar, puede escribir sus propias rutinas de asignación de memoria basándose en su patrón de uso previsto. Por ejemplo, podrías tener una rutina separada para cada hilo de ejecución. Si puedes garantizar que free() ocurre en orden inverso a alloc() entonces puedes usar un simple puntero al final de la memoria.

O puedes utilizar un nivel de indirección: Acceder a la memoria sólo a través de un puntero a un puntero. Entonces puedes recoger libremente la memoria y ajustar la tabla de punteros para que apunte a la memoria donde quiera que acabe.

La mejor respuesta para los sistemas embebidos suele ser evitar por completo la asignación dinámica de memoria.

0voto

Javier Loureiro Puntos 21

Después de montones y montones de comentarios y respuestas de no usar memoria dinámica, todavía encontré una forma que en ese momento solucionaba mi problema.

He cambiado esto en mi código

typedef struct
{
    task_t task;
    uint8_t next;
    uint8_t prev;
    uint8_t priority;

} info_t;

typedef struct
{
    task_t task;
    uint8_t index;
} index_t;

typedef struct
{
    info_t m_info;
    info_t m_index;
} combined_t;

combined_t* m_combined;

Con esto, nw mi realloc() asigna memoria contigua a m_combined y mi problema de fragmentación está resuelto. (Bueno supongo que porque después de analizar la memoria paso a paso).

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X