Asignación dinámica de memoria para una aplicación integrada

Estoy trabajando en un proyecto que requerirá el uso de una MCU para recibir paquetes de cuadros con una longitud de cuadro desconocida en la recepción, pero cada recepción tiene un octeto a partir del cual puede deducir la cantidad de cuadros que quedan por recibir y, por lo tanto, calcular la longitud del cuadro completo. .

En otro caso, para evitar asignar una memoria fija para el marco de recepción que podría no agotarse (si la longitud del marco de recepción es menor que la longitud máxima del marco para recibir), soy de la opinión de asignar dinámicamente una memoria para el marco restante para ser recibido.

Por ejemplo. Si asumimos paquetes de 20 octetos y el tercer octeto le dice el número de octetos restantes que quedan por recibir (que podrían ser 2, 3, incluso 17 octetos como máximo). En lugar de crear un registro de tamaño 17, que podría no agotarse, ¿cómo puedo asignar dinámicamente esta memoria especialmente para una aplicación integrada, de modo que si el tercer octeto revela que hay 6 octetos para recibir, entonces simplemente asigno un registre con tamaño 6 para el resto del marco, sin usar el "malloc".

El lenguaje de programación es C.

Espero que mi pregunta sea lo suficientemente clara. Comparta sus opiniones, ya que necesito el mejor enfoque posible sobre esto.

Gracias.

¿Alguna razón por la que no quieras usar malloc?
¿Qué ventaja te da no usar la memoria extra? Aún debe dimensionar la MCU para tener suficiente RAM para el paquete más grande que pueda recibir.
@Bruno, ¿Aconsejaría el uso de malloc para una aplicación integrada, de un tamaño de RAM de aproximadamente 2K, y pensando en el hecho de que las memorias están conjugadas?
@markrages Entiendo su punto, pero quiero ver si hay alguna forma de ayudar a ahorrar memoria, porque el tamaño máximo real es de aproximadamente 128 bytes, que no siempre se agota por completo, entonces, ¿por qué no ayudar a utilizar la memoria restante para otras operaciones? ?
¿Qué vas a hacer con el resto? Debe estar listo para que llegue el tamaño máximo de paquete, ¿no?
@PaulA. Eso depende de la cantidad de memoria libre que tengas. Tenga en cuenta que el uso de un esquema de asignación dinámica siempre tiene una sobrecarga, por lo que si el tamaño de sus datos no es mucho mayor que 20 bytes, entonces puede ser mejor usar bloques de tamaño fijo.
Debe dar más detalles sobre lo que quiere decir con "una MCU". Si está hablando de un pequeño procesador incorporado que no hace nada más, la respuesta es, comprometa toda su memoria al trabajo, no se preocupe por la asignación dinámica. Si se trata de un ARM de 32 bits que ejecuta Linux y hay muchas otras cosas que usan memoria, entonces sí, vuélvete dinámico. ¿Cuánta memoria hay en el sistema y qué más la está usando?

Respuestas (2)

En este caso, diría que el mejor enfoque es probablemente solo asignar el tamaño máximo de memoria y reutilizarlo para tantas otras cosas como sea posible también.
Algunos compiladores tienen una opción para que las variables compartan espacio de memoria siempre que no estén activas al mismo tiempo. Por ejemplo, el compilador PIC18 C (ahora reemplazado por HI-Tech C) tiene un overlayatributo que se puede usar con variables para hacer esto.
También puede manejar matrices de tamaño variable que serían perfectas para lo que desea hacer (menos gastos generales que malloc). Verificaría si su compilador puede hacer esto.

@oil Glaser. Gracias por este punto. Uso el compilador Keil y el Atmel Studio 6. ¡Sé si tienen esas características!
De acuerdo, esto parece un mal caso para la asignación dinámica, especialmente en una plataforma integrada; la asignación dinámica es más útil cuando literalmente no sabe cuánta memoria se necesitará, es decir, la interacción del usuario provoca la asignación de memoria. A menos que me esté perdiendo algo, parece que necesita suficiente espacio para la cantidad máxima de paquetes de tamaño máximo en el peor de los casos, entonces, ¿por qué no asignar tanta memoria en lugar de diseñar una solución en exceso? Además, si sigue la ruta dinámica en una plataforma con memoria limitada y no tiene cuidado, el amigo gruñón de la asignación dinámica, Fragmentation, lo morderá.

En muchos sistemas de microcontroladores, los compiladores y enlazadores asignan datos desde la parte inferior y/o superior de la RAM; La RAM no utilizada generalmente estará en un área contigua y, por lo general, es posible convencer al enlazador de que ponga a disposición del programador las direcciones de inicio y final de esa área (por ejemplo, se podría pedir al enlazador que coloque una variable de un byte como el lo último antes del área libre, y otro como lo primero que sigue; las direcciones de esas variables delimitarían el espacio libre).

Aunque muchos sistemas ofrecen una malloc()función, es más complicada de lo necesario en muchos escenarios. Por ejemplo, si necesita asignar objetos en función de la información recibida en tiempo de ejecución, pero los objetos siempre se liberarán en el orden inverso de asignación, simplemente puede mantener un puntero al "siguiente espacio disponible". Para asignar un objeto, copie ese puntero, agregue el tamaño del nuevo objeto y devuelva el puntero copiado. Para liberar un objeto (y todo lo asignado después de él), simplemente coloque el puntero de "siguiente espacio disponible" al comienzo de ese objeto.

Algunos escenarios son un poco más complejos de lo que se permitiría con ese enfoque, pero aún así no necesitan un enfoque completo "malloc/free". Por ejemplo, en algunos escenarios, uno puede tener dos grupos de objetos que obedezcan la regla de último en entrar, primero en salir entre ellos, pero los objetos de un grupo pueden sobrevivir a los del otro. Para hacer frente a esa situación, utilice un puntero de "espacio disponible siguiente" que comienza en la parte inferior del espacio libre y un puntero de "espacio disponible anterior" que comienza en la parte superior. Asigne las cosas en el primer grupo como antes. Para aquellos en el segundo grupo, reste el tamaño del nuevo objeto del puntero de "espacio disponible anterior" y devuelva el resultado. Para liberar un objeto del segundo grupo (y todos los objetos del segundo grupo asignados después),

Tenga en cuenta que mallocyfreeestán diseñados para que sea posible liberar objetos en el medio de la memoria, mientras que los objetos anteriores y posteriores siguen siendo válidos. Si bien esto a veces puede ser útil, también puede conducir a la fragmentación de la memoria. Si los objetos de uno no encajan con un modelo de último en entrar, primero en salir, puede ser una buena idea hacer que los objetos sean reubicables. Por ejemplo, uno podría mantener una cola de objetos de tamaño variable que se almacenan consecutivamente en la memoria siempre que haya espacio. Cuando la memoria se llena (o en algún momento conveniente antes de eso), uno copiaría el primer objeto que aún no se había leído al comienzo de la cola, el siguiente objeto que no se había leído inmediatamente después, etc. hasta todos los objetos habían sido copiados, consolidando el espacio libre que había al principio de la cola, hasta el final. Se debe tener cuidado al mover cualquier dato para asegurarse de que los punteros a esos datos se actualicen en consecuencia, pero eso a menudo no es demasiado difícil. Mover la memoria puede requerir más ciclos de CPU que administrar áreas discontinuas de espacio libre, pero el comportamiento del enfoque de memoria móvil puede ser más predecible.