Experimento csapp Explicación detallada del experimento 8-malloclab

8-malloclab

Bienvenido al blog del autor sakura sin ropa de pera pintada.

Este experimento debe considerarse como el más difícil, con varios indicadores superpuestos, pero también es un experimento clásico como el laboratorio de bombas.

1 Breve análisis

Propósito del experimento: familiarizarse con los punteros del lenguaje C, familiarizarse con el método de aplicación de la memoria dinámica y la estructura de la memoria dinámica.

Espacio de trabajo: mm.c

Contenido del experimento: escriba un asignador de almacenamiento dinámico para implementar operaciones init, malloc, realloc, free y otras, y optimice este asignador tanto como sea posible para equilibrar el rendimiento y la utilización del espacio.

Herramienta experimental: herramienta mdriver, que puede detectar la corrección

2 Implementación específica

1. Estructura del montón

El montón es el área de memoria virtual de un proceso. Primero mira la estructura del montón.

Insertar descripción de la imagen aquí

La dirección del montón es continua y toda el área de memoria es el montón, entonces, ¿cómo administrar toda esta área de memoria? Hay tres formas comunes

  1. Lista libre implícita:
    • Divida todo el montón en muchos bloques adyacentes. El encabezado de cada bloque contiene información sobre el tamaño del bloque y si ha sido asignado. A través del tamaño de este bloque, podemos encontrar el inicio del siguiente bloque conectado a él. dirección
    • Ventajas: Sencillo
    • Desventajas: cada aplicación debe recorrerse desde cero, el rendimiento es bajo y es fácil generar mucha fragmentación del espacio.
  2. Listas gratuitas explícitas:
    • Una mejora en la lista libre implícita. Basada en la lista libre implícita, cada bloque libre no solo almacena su tamaño e información sobre si está asignado, sino que también almacena un puntero al bloque libre siguiente y/o anterior, de modo que al mirar para bloques libres, solo necesitas recorrer la lista libre
    • Beneficios: eficiencia de asignación de memoria mejorada y fragmentación de espacio reducida
    • Desventajas: requiere mucho espacio para almacenar punteros, es difícil de mantener,
  3. Listas libres segregadas:
    • Mantenga varias listas libres, los bloques de cada lista sean aproximadamente iguales en tamaño y el asignador mantenga una serie de listas libres.
    • Beneficios: mejora la eficiencia de la asignación de memoria y reduce la fragmentación del espacio
    • Desventajas: Difícil de mantener, puede llevar a una baja utilización del espacio.

Nuestro propósito: equilibrar la tasa de rendimiento y la utilización del espacio (estos dos en realidad están en conflicto. Es imposible tener una alta tasa de rendimiento y una alta tasa de utilización del espacio, porque una alta tasa de rendimiento debe utilizar estructuras como listas vinculadas, tablas hash, árboles, etc. Estas estructuras conducirán inevitablemente a una menor utilización del espacio, por lo que debe haber un equilibrio)

2. Estructura de bloques

Eche un vistazo a la estructura del bloque para facilitar la comprensión del código.

Insertar descripción de la imagen aquí

3. Implementación

Tenga en cuenta que todas las etapas del código provienen de CSAPP | Lab8-Malloc Lab Análisis en profundidad - Zhihu (zhihu.com) , el jefe es demasiado asombroso, lo explicaré brevemente aquí.

  1. Primero, defina un conjunto de macros que sean fáciles de operar. Creo que este conjunto de macros es un golpe de genialidad. El papel de las macros es muy claro, así que no lo explicaré.
/* 头部/脚部大小 单字(四字节) */
#define WSIZE 4
/* 双字 */
#define DSIZE 8

/* 取最大值 */
#define MAX(a, b) ((a) > (b) ? (a) : (b))

/* 扩展堆时默认大小 */
#define CHUNKSIZE (1 << 12)

/* 设置头部/脚部值 */
#define PACK(size, alloc) ((size)|(alloc))

/* 读写指针p */
/*
	首先知道void*类型的指针可以指向任何地方,其实malloc函数申请的指针就是void*类型
	(unsigned int *)(p)的意思是将void*类型的指针p强转为指向unsigned int类型的指针
	然后(*(unsigned int *)(p))是取出该指针指向的unsigned int类型的值
*/
#define GET(p) (*(unsigned int *)(p))
#define PUT(p, val) ((*(unsigned int *)(p)) = (val))

/* 从头部或脚部获取大小或分配位 */
/* 这里0x是十六进制嗷,低一位表示是否已分配 */
#define GET_SIZE(p) (GET(p) & ~0x7)
#define GET_ALLOC(p) (GET(p) & 0x1)

/* 给定有效载荷指针,找到头部和脚部 */
#define HDRP(bp) ((char *)(bp) - WSIZE)
#define FTRP(bp) ((char *)(bp) + GET_SIZE(HDRP(bp)) - DSIZE)

/* 给定有效载荷指针, 找到前一块或下一块 */
#define NEXT_BLKP(bp) ((char*)(bp) + GET_SIZE(((char*)(bp) - WSIZE)))
#define PREV_BLKP(bp) ((char*)(bp) - GET_SIZE(((char*)(bp) - DSIZE)))
  1. Luego define las funciones que necesitas usar, cada función está comentada aquí.
/**
 * @brief 初始化堆
 * 初始化一个堆,主要是定义了堆的序言块和结尾块,相当于开头和结尾,然后添加了一个CHUNKSIZE/WSIZE大小的空  间
 */
int mm_init(void);

/**
 * @brief 扩展堆
 * 用于扩展堆,每当需要申请动态内存的时候就调用该函数来申请动态内存空间
 *
 * @param words	申请的动态内存大小
 */
void *extend_heap(size_t words);

/**
 * @brief 释放内存
 *
 * @param ptr	需要释放的块指针
 */
void mm_free(void *ptr);

/**
 * @brief 分割空闲块
 * 判断剩下的空间是否足够存放头部和脚部,够的话就设置各种标志位,不够的话就要设置为填充的块
 *
 * @param bp	当前空闲块指针
 * @param asize	当前请求的块大小
 */
void place(void *bp, size_t asize);

/**
 * @brief 合并块
 * 合并块有四种情况,需要把相邻的空闲块合并在一起
 *
 * @param bp	需要合并的块指针
 */
void *coalesce(void *bp);

/**
 * @brief 首次适配原则
 *
 * @param asize	请求的块大小
 */
void *first_fit(size_t asize);

/**
 * @brief 自主实现的malloc
 *
 * @param size	申请的块大小
 */
void *mm_malloc(size_t size);

/**
 * @brief 重新申请块大小
 *
 * @param ptr	重新申请的块的指针
 * @param size	重新申请的块大小
 */
void *mm_realloc(void *ptr, size_t size);

El siguiente es el código de cada parte, los comentarios dados por el jefe para cada función en esta parte son muy detallados, no seré demasiado feo, así que puedes leerlo lentamente.

Resumen: Por fin más picante. Aunque el último experimento fue más acuoso, finalmente se terminó. Esté lleno de energía a partir de ahora ~

Supongo que te gusta

Origin blog.csdn.net/m0_65591847/article/details/132922447
Recomendado
Clasificación