2009-11-12 20 views
13

Por lo tanto, en una unidad de sistemas integrados, que tomaré en la universidad el próximo año, aprenderemos que las estructuras de datos dinámicas son algo malo de tener en un programa de sistema integrado. pero las notas de la conferencia no explican por qué.¿Qué tan malo es usar estructuras de datos dinámicas en un sistema integrado?

Ahora estoy trabajando en una escala moderada, el controlador \ LURC integrado de sistemas, sobre todo solo aprovecha las ventajas del periférico de la placa de demostración "Mariposa" para el AVR169MEGA. produjo 4 señales PWM para controlar los servo y ESC. y también para proporcionar una pantalla LCD de 9 seg.

Ahora no se me ocurre ninguna manera mejor de almacenar las instrucciones, ya que se reciben en el vial serie de USART, que en una cola. esp para cosas donde tendré que esperar hasta que se reciba una cantidad desconocida de datos: por ejemplo, una cadena para mostrar en la pantalla LCD.

¿por qué no utiliza estructuras de datos dinámicas en un microcontrolador en un sistema integrado? ¿Es solo que estás en un ambiente con mucha memoria restringida y tienes que estar seguro de que tus mallocs están teniendo éxito?

+1

esto: http://www.nongnu.org/avr-libc/user-manual/malloc.html es tranquilo bueno –

Respuesta

18

Existen varias razones para no utilizar malloc (o equivalente) en un sistema integrado.

  • Como mencionaste, es importante que no te encuentres repentinamente sin memoria.
  • Los sistemas embebidos en fragmentación pueden funcionar durante años y pueden causar una gran pérdida de memoria debido a la fragmentación.
  • Realmente no es necesario. La asignación de memoria dinámica le permite reutilizar la misma memoria para hacer cosas diferentes en momentos diferentes. Los sistemas integrados tienden a hacer lo mismo todo el tiempo (excepto al inicio).
  • Velocidad.La asignación de memoria dinámica es relativamente lenta (y se vuelve más lenta a medida que la memoria se fragmenta) o es bastante derrochadora (por ejemplo, el sistema de amigos).
  • Si va a utilizar la misma memoria dinámica para diferentes subprocesos e interrupciones, las rutinas de asignación/liberación deben realizar el bloqueo, lo que puede causar problemas en el mantenimiento de las interrupciones lo suficientemente rápido.
  • La asignación de memoria dinámica dificulta la depuración, especialmente con algunas de las herramientas de depuración limitadas/primitivas disponibles en el sistema integrado. Si distribuye material estáticamente, sabe dónde está todo el tiempo, lo que significa que es mucho más fácil inspeccionar el estado de algo.

Lo mejor de todo: si no asigna dinámicamente la memoria, no podrá obtener pérdidas de memoria.

+0

Si bien estoy aceptando esto como la respuesta, todavía está incompleto. ya que echa de menos una de las grandes razones. (sin embargo coivers la mayoría de los demás) La memoria asignada dinámicamente puede sobrescribir muy fácilmente la pila de la CPU. –

+1

"La memoria asignada dinámicamente puede sobrescribir muy fácilmente la pila de la CPU". -- Esto no es realmente cierto. De hecho, es la * pila * que es dinámica por naturaleza y puede crecer para sobrescribir la memoria asignada. La memoria que no es de pila tendrá un límite superior establecido para la asignación dinámica y estática, pero cuando la pila crece más allá de las expectativas, simplemente sobrescribe los datos que no deberían, independientemente de si están asignados estáticamente o no. La pila no está más amenazada cuando se usa la asignación dinámica. – JimmyB

0

Diría tanto la falta de memoria como el problema de un malloc fallido. Esto último es más un problema ya que no tiene una interfaz OS/para rescatar el sistema de dicha falla. Es muy peligroso usar una función que puede poner a tu sistema completo sin cabeza en un frenazo (o quizás causar un reinicio, aún mal).

4

Bueno, muchos microcontroladores más pequeños no tienen nada como una MMU, o un sistema operativo con un buen montón para que usted pueda trabajar.

Para aquellos que sí lo hacen, siempre y cuando mantenga una buena conexión con la cantidad de memoria que está pidiendo, realmente no veo un gran problema con ella.

Sin embargo, muchos sistemas integrados también son Real Time sistemas. Si su aplicación tiene fechas límite estrictas respecto al tiempo que le llevará ejecutarse, tendrá problemas con las asignaciones dinámicas. La mayoría de las implementaciones de montón utilizan algoritmos que no tienen un tiempo de ejecución muy limitado. En algunos casos (quizás raros), tardarán más en ejecutarse waaaay de lo normal. Hay algunas implementaciones de heap en tiempo real, pero no son muy utilizadas. La regla general es evitar cualquier asignación dinámica o desasignación en un sistema en tiempo real después de la inicialización.

3

Mi impresión es que en un sistema integrado, sé exactamente cuánta memoria hay disponible, y puedo usar exactamente el 100% de ella; no hay necesidad de dejar un poco para otros programas (que se ejecutan simultáneamente), pero tampoco hay memoria virtual disponible para darme el 101 por ciento. Entonces, para una cola, puedo calcular fácilmente que tengo espacio para (digamos) 981 registros; así que creo una matriz para esos registros y si alguna vez necesito un 982º registro, estoy confundido y debo encontrar una forma de fallar con elegancia.

+0

La mayor parte de mi trabajo incrustado ha sido en trabajos del gobierno, donde hay un requisito de rutina para dejar el 50% repuesto para futuras actualizaciones. ¿El mundo comercial no hace esto? –

+0

T.E.D. ese es un consejo sabio que he aprendido de ti – bazz

0

Las estructuras de datos dinámicas en los sistemas integrados son un poco como punteros en C++. Los punteros (en C++) son malvados. Pero a veces son la única opción; a veces son el mal menor; y a veces está bien evitarlos por completo. En los casos en que es una buena razón para usarlos, puede haber "buenas" maneras y "malas" maneras de hacerlo.

Las matrices y las variables asignadas de forma estática son mucho más rápidas de asignar y desasignar, y pueden tener un acceso más rápido, que los datos asignados dinámicamente. Ver this answer.

asignados dinámicamente (por lo cual quiero decir malloc() ed o similar) de datos también requiere espacio gastos generales para realizar un seguimiento de las asignaciones. Varios bytes por asignación como mínimo: ¡este espacio puede ser muy valioso en los sistemas integrados!

Las pérdidas de memoria son un problema masivo en los sistemas integrados, que a veces se puede esperar que se ejecuten durante años. Evitar la asignación dinámica es prudente desde esta perspectiva.

Los dispositivos integrados generalmente tienen especificaciones bastante confiables. Usted sabe cuál es la tasa de transferencia, usted sabe qué tan rápido puede manejar la información, y así sucesivamente. En su ejemplo, la solución es usar un buffer de tamaño fijo como circular queue. Haga que el buffer sea lo suficientemente grande como para manejar lo que su dispositivo necesita para ser capaz de manejar (y quizás un poquito más). Si llegan demasiados datos, es probable que se deba a una falla o interferencia en otro lugar de todos modos, así que no tiene sentido mantener e intentar usar toda esa información.

4

Depende del significado de "incrustado" en mi opinión ampliada en los últimos 4 años.

Tradicionalmente, los dispositivos integrados tenían microcontroladores y generalmente ningún sistema operativo. Sin memoria protegida, y eran de un solo hilo. Tendría que ser extremadamente cuidadoso con la memoria mal colocada porque es muy fácil quedarse sin ella cuando solo tiene 32 KB disponibles, por ejemplo. Por lo tanto, en general, escribimos nuestro código con búferes de tamaño fijo y nunca utilizamos malloc o en caso de que se usen todos, muy poco.

En los últimos años, estamos viendo lo que son esencialmente PCs de un solo chip o micro placas que son tan poderosas como nuestras antiguas PC Pentium. Los precios de RAM ahora son tan baratos y tan pequeños que las limitaciones de memoria no se parecen en nada a lo que eran. También suelen ejecutar Linux embebido o wince por lo que ahora tenemos la capacidad de utilizar la memoria dinámica de forma más liberal.

Con esto es posible utilizar una gama mucho más amplia de idiomas, incluidos Java, C++, muchos lenguajes de scripting y otros lenguajes que proporcionan protección de desbordamiento de búfer y manejo de excepciones y otros lenguajes de nivel superior. Entonces, realmente, esos viejos problemas no son como solían ser.

Sospecho que todo este nuevo hardware disponible presenta una nueva gama de problemas.

+0

32 KB de RAM! tuviste suerte. Tengo 1 Kb de RAM (todos los 26 de nosotros) que tengo que compartir tit él la pila de la CPU –

0

No conozco el Atmel MEGA169, pero el MEGA168, que supongo está relacionado con el 169, tiene solo 1024 bytes de SRAM. También tiene solo 16k de ROM de programa, y ​​es relativamente lento en comparación con las computadoras modernas. Por lo tanto, está limitado en memoria, tamaño de programa y velocidad.

En mi experiencia con la programación del ensamblador AVR, se requiere un gran esfuerzo para incorporar tanta funcionalidad al PIC como sea posible. La cantidad de sobrecarga necesaria para usar estructuras de datos dinámicas (uso de memoria adicional, instrucciones adicionales necesarias para extraer y enviar datos de SRAM, realizar un seguimiento de qué variable dinámica reside en dónde, mover bloques de memoria cuando se eliminan las variables intermedias). ..) simplemente no justifica los méritos.

Así que incluso si el compilador lo implementa me quedaría con estructuras de datos estáticos para el rendimiento.

+0

PIC? OP está preguntando por los AVR. – iter

+0

También estaba hablando de AVR. Mi error. – thomaspaulb

2

No hay nada de malo con la memoria dinámica en un entorno incrustado per se, aunque generalmente no le compra mucho en un entorno incrustado.

En mi opinión es una muy buena idea usar los buffers de anillo (esta es una estructura de datos muy común para controladores de E/S, etc.). De esta forma, si por alguna razón no puede atender su cola, el uso de memoria sigue siendo determinista.

Usando algunas macros es posible asignar estructuras de tamaño variable en tiempo de compilación.

Por ejemplo -

//we exploit the fact that C doesn't check array indices to allow dynamic alloc of this struct 
    typedef struct ring_buf_t { 
     int element_sz, 
      buffer_sz, 
      head, 
      tail; 
     char data[0]; 
    } ring_buf_t; 

    #define RING_BUF_ALLOC_SZ(element_sz,n_elements) (sizeof (ring_buf_t) + \ 
                 (element_sz) * (n_elements)) 

    char backing_buf[RING_BUF_ALLOC_SZ (sizeof(type_to_buffer), 16)]; 

    //ring_buf_init() casts backing buf ring_buf_t and initialises members... 
    ring_buf_t *ring_buffer = ring_buf_init (element_sz, n_elemements, backing_buf); 

;

Este patrón es un búfer dinámicamente considerable con uso de memoria garantizado. Por supuesto, otras estructuras de datos de tipo (listas, colas, etc.) se pueden implementar de la misma manera.

Cuestiones relacionadas