¿Por qué la función malloc de mi atmega32 me devuelve la dirección del puntero en múltiplo de 4?

5

Estoy en una fase de aprendizaje, por lo que no soy un profesional a la hora de entender la memoria y, por lo tanto, me cuesta un poco entender algunas cosas

  1. La hoja de datos de atmega32 dice que viene con 2K de SRAM

¿Cómohaceesto2k?

  • Cuando ejecuté el siguiente código en un bucle infinito hasta que devuelve 0, la función malloc me devolvió las direcciones en múltiplos de 4 para Atmega32.

    p = (char*)malloc(sizeof(char));
    

    Por lo que estoy entendiendo, el carácter es de 1 byte, por lo tanto, ¿debería darme las direcciones adyacentes?

  • pregunta MaNyYaCk

    3 respuestas

    11

    Para la primera pregunta:

    Hay 2kB de SRAM. Hay 32 bytes adicionales de registros de CPU, y otros 64 bytes de registros de E / S (cosas como los registros PORTA / DDRA / etc).

    Agregue estos todos hasta obtener 2048 + 32 + 64 = 2144 bytes de memoria direccionable. Convierte eso a hexadecimal y obtienes 0x860, o en términos de dirección 0x000 a 0x85F.

    La memoria SRAM en sí misma es el bloque de 2kB de 0x060 a 0x85F.

    Para la segunda pregunta:

    malloc usa una llamada "lista de distribución gratuita" que mantiene qué trozos de memoria están disponibles para asignar o reasignar. Esta lista se almacena en la misma SRAM que la memoria que está asignando, y se actualiza sobre la marcha a medida que usa la memoria de asignación.

    Cada entrada en la lista gratuita es un puntero de 16 bits, que apunta a la siguiente entrada que forma una cadena, cada entrada hace un seguimiento de dónde está la próxima entrada, y un tamaño de 16 bits que dice qué tan grande es el bloque actual.

    Como resultado, cada bloque de memoria asignado mediante malloc debe tener un tamaño de al menos 4 bytes para almacenar la entrada de la lista. Cuando solicita un solo byte de memoria, tiene que redondear hasta 4 bytes para que cuando esa memoria se desasigne, haya espacio para que se almacene una entrada en la lista.

    En lugar de entrar en detalles exactos, el enfoque de listas de distribución se explica en la documentación de avr-libc aquí . La siguiente cita explica la necesidad

      

    La lista de distribución en sí misma no se mantiene como una estructura de datos separada, sino más bien modificando el contenido de la memoria liberada para que contenga punteros que encadenan las piezas. De esa manera, no se requiere memoria adicional para mantener esta lista, excepto por una variable que realiza un seguimiento del segmento de memoria más bajo disponible para la reasignación. Dado que tanto el puntero de la cadena como el tamaño del fragmento deben registrarse en cada fragmento, el tamaño mínimo del fragmento en la lista de distribución libre es de cuatro bytes

    Si no puedes entenderlo (el proceso no es obvio de inmediato), no debes preocuparte. Lo más simple que debes recordar es que cada fragmento que malloc tendrá un tamaño de al menos 4 bytes, incluso si solo quieres 1.

    También vale la pena señalar después de un poco de experimentación, la cantidad de memoria asignada parece ser siempre la mayor de 4 bytes, o la cantidad solicitada + 2 bytes. Por ejemplo, si solicita 3 bytes, entonces se asignarán 5 bytes. Si pides 8 bytes obtendrás 10.

    En cuanto a por qué se asignan los 2 bytes adicionales, no estoy seguro. No puedo encontrar referencias a esto en la documentación de avr-libc.

        
    respondido por el Tom Carpenter
    3

    Permítame explicarle los resultados más detallados anotados por Tom Carpenter en los comentarios:

      

    cualquier solicitud a malloc parece asignar el mayor de 4 bytes o la cantidad requerida + 2 bytes

    Cualquier solicitud necesita 2 bytes adicionales de sobrecarga. Esto registrará el tamaño del bloque, por lo que free sabe exactamente qué reclamar. Con granularidad de 1 byte y 2K para realizar un seguimiento de, necesita 14 bits para este tamaño. Eso cabe en 2 bytes.

    Un nodo en la lista gratuita utiliza la memoria libre para realizar un seguimiento de la memoria libre. Necesita el tamaño, igual que el nodo asignado. Pero también necesita un puntero al siguiente nodo libre , que toma otros 2 bytes. Por lo tanto, cualquier bloque que deba liberarse debe tener al menos 4 bytes en total (2 bytes dados para usar y 2 para el tamaño del bloque asignado).

    Por lo tanto, si solicita 1 byte, debe asignar 2 y tomar otros 2 para la sobrecarga. Más generalmente, se necesitan 2 bytes adicionales para la sobrecarga y nunca deja un bloque libre que sería demasiado pequeño para un nodo libre. Es decir, si solicitó (por ejemplo) 19 bytes y la lista libre tenía un nodo de 24 bytes, no podría separar 19 + 2 y dejar 2 + 1 atrás: asignaría todo a pesar de que es de 3 bytes más que solicitado.

    Estoy familiarizado con el funcionamiento del montón porque, en 1983, leí El arte de la programación informática y lo he implementado en múltiples ocasiones.

        
    respondido por el JDługosz
    1

    El problema está relacionado con la alineación de la memoria. A menudo, los procesadores tienen una limitación de que, al acceder a un tipo de datos de 32 bits, deben hacerlo utilizando una dirección que sea un múltiplo de 4. Este es solo un ejemplo de una restricción de alineación.

    malloc() es requerido por el estándar C para devolver una dirección con alineación máxima para que CUALQUIER tipo de datos pueda almacenarse en esa dirección. malloc() no sabe para qué tipo de datos usará la dirección.

    Probablemente, malloc() está devolviendo múltiplos de 4 porque este procesador lo requiere para algunos tipos de datos.

    Esta pregunta podría ser mejor para un foro de programación.

        
    respondido por el mkeith

    Lea otras preguntas en las etiquetas