Alineación y división
Haga que los bloques sean utilizables y estén organizados
Alineación y división es una lección gratuita de C Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C Academy incluye 4 lecciones en total.
Por qué importa la alineación
Cada tipo tiene un requisito de alineación: su dirección debe ser múltiplo de una potencia de dos. Un double normalmente necesita una alineación de 8 bytes.
Como malloc no sabe qué va a almacenar, debe devolver punteros alineados para el tipo más exigente, normalmente 16 bytes en sistemas de 64 bits.
#include <stdalign.h>
/* the strictest fundamental alignment */
size_t strict = alignof(max_align_t); /* often 16 */El truco de align_up
Redondear un tamaño hacia arriba hasta el siguiente múltiplo de una alineación que sea potencia de dos es un truco clásico de bits: sume a - 1 y después enmascare los bits inferiores.
Esto solo funciona cuando a es una potencia de dos, que es el caso de todas las alineaciones reales.
static size_t align_up(size_t n, size_t a) {
return (n + a - 1) & ~(a - 1);
}
/* align_up(13, 8) == 16, align_up(16, 8) == 16 */Verificación práctica de las matemáticas
Verifiquemos align_up con un programa ejecutable. Redondea varios tamaños hasta límites de 8 y 16 bytes y muestra los resultados.
#include <stdio.h>
#include <stddef.h>
static size_t align_up(size_t n, size_t a) {
return (n + a - 1) & ~(a - 1);
}
int main(void) {
printf("%zu\n", align_up(13, 8)); /* 16 */
printf("%zu\n", align_up(16, 8)); /* 16 */
printf("%zu\n", align_up(1, 16)); /* 16 */
printf("%zu\n", align_up(33, 16)); /* 48 */
return 0;
}Alineación de los tamaños solicitados
Dentro del asignador, el primer paso de cada solicitud es redondear el tamaño solicitado hasta la alineación. Esto garantiza que el siguiente bloque también comience alineado.
Los bytes de relleno son fragmentación interna: el precio de la alineación universal.
#define ALIGN 16
void *my_alloc(size_t size) {
size = align_up(size, ALIGN);
/* now find a block of this aligned size */
/* ... */
return NULL;
}El problema de reutilizar bloques completos
En la lección anterior devolvíamos un bloque libre entero incluso para solicitudes diminutas. Entregar un bloque libre de 4000 bytes para una solicitud de 16 bytes desperdicia el resto.
La división separa el bloque en la parte que usamos y un resto que permanece libre.
División de un bloque
Si el bloque elegido es mucho mayor de lo necesario, colocamos una nueva cabecera al final de la región solicitada. El espacio restante se convierte en un bloque libre más pequeño de la lista.
Solo dividimos cuando el resto es lo bastante grande para contener una cabecera y algo de carga útil; de lo contrario, el fragmento no sirve.
void split(block_t *b, size_t size) {
size_t rem = b->size - size;
if (rem < sizeof(block_t) + ALIGN) return; /* too small */
block_t *nb = (block_t *)((char *)(b + 1) + size);
nb->size = rem - sizeof(block_t);
nb->free = 1;
nb->next = b->next;
b->size = size;
b->next = nb;
}Asignar, alinear y dividir
Ahora el proceso completo de asignación alinea el tamaño, encuentra un bloque adecuado, separa cualquier resto grande y marca el bloque como usado.
Esto mantiene los bloques ajustados a su tamaño y deja espacio libre utilizable.
void *my_alloc(size_t size) {
size = align_up(size, ALIGN);
block_t *b = first_fit(size);
if (!b) return NULL;
split(b, size);
b->free = 0;
return (void *)(b + 1);
}Mantener alineado el propio conjunto
Para garantizar la corrección, la dirección inicial del conjunto y el tamaño de la cabecera también deben respetar la alineación, de modo que cada carga útil caiga en un límite.
Usar alignas en el búfer estático garantiza que todo el esquema comience alineado.
#include <stdalign.h>
alignas(16) static unsigned char pool[4096];
/* pool now begins on a 16-byte boundary */Una asignación alineada ejecutable
Este programa asigna memoria desde un conjunto alineado y muestra la dirección devuelta módulo 16, demostrando que siempre es cero, es decir, que está correctamente alineada.
#include <stdio.h>
#include <stddef.h>
#include <stdalign.h>
static size_t align_up(size_t n, size_t a){ return (n+a-1)&~(a-1); }
alignas(16) static unsigned char pool[1024];
static size_t off = 0;
void *alloc16(size_t s){ off=align_up(off,16); if(off+s>sizeof(pool)) return NULL; void*p=&pool[off]; off+=s; return p; }
int main(void){
void *a = alloc16(1);
void *b = alloc16(20);
printf("a %% 16 = %lu\n", (unsigned long)((size_t)a % 16));
printf("b %% 16 = %lu\n", (unsigned long)((size_t)b % 16));
return 0;
}División frente a fusión
La división y la fusión son opuestas y se equilibran entre sí. La asignación divide los bloques grandes; la liberación vuelve a fusionar los bloques pequeños.
Juntas permiten que el mismo conjunto atienda una combinación cambiante de tamaños de solicitud sin perder espacio ni fragmentarse de forma permanente.
Del asignador de prueba al asignador real
Ahora cuenta con los cuatro pilares: una fuente de memoria, cabeceras alineadas, reutilización mediante una lista libre con fusión y división. Los asignadores reales añaden contenedores por clase de tamaño, cachés de hilos e integración con el sistema operativo para ganar velocidad y escala.
Pero las ideas fundamentales que ha desarrollado aquí impulsan todas las implementaciones de malloc.
Comprobación rápida
Considere por qué se dividen los bloques durante la asignación.
Resumen
La alineación redondea los tamaños hacia arriba con el truco de bits (n + a - 1) & ~(a - 1), de modo que cada carga útil sea adecuada para cualquier tipo. La división separa los bloques libres sobredimensionados en una parte usada y un resto libre, mientras que la fusión invierte el proceso al liberar.
Estos cuatro pilares forman juntos un asignador de memoria completo y correcto.
Preguntas frecuentes
¿La lección «Alineación y división» es gratis?
Sí — el texto completo de «Alineación y división» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C Academy, actualiza a CoddyKit PRO. El curso de C Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Alineación y división»?
Haga que los bloques sean utilizables y estén organizados Practicas C Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar C Academy?
No se requiere experiencia previa. C Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.
¿Cuánto tiempo toma la lección «Alineación y división»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de C Academy?
Sí. Cada lección de C Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Cómo funciona malloc
- Un asignador bump sencillo
- Listas libres y reutilización
- Alineación y división