概述
在项目上,经常遇到芯片内存不够导致编码困扰问题,在此写个笔录,方便后续查阅。
此示例,考虑了一些额外的功能和边界条件,例如内存分配的对齐、内存池的重用等。这个示例使用了双向链表来管理内存块。
源码如下:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>// 内存块结构
typedef struct MemoryBlock {size_t size; // 内存块大小struct MemoryBlock* prev; // 前一个内存块的指针struct MemoryBlock* next; // 下一个内存块的指针
} MemoryBlock;// 内存池结构
typedef struct MemoryPool {size_t totalSize; // 内存池总大小MemoryBlock* firstBlock; // 内存池中第一个内存块的指针
} MemoryPool;// 初始化内存池
void memoryPoolInit(MemoryPool* pool, size_t totalSize)
{pool->totalSize = totalSize;pool->firstBlock = (MemoryBlock*)malloc(totalSize);if (pool->firstBlock == NULL) {fprintf(stderr, "Failed to allocate memory for memory pool\n");exit(EXIT_FAILURE);}pool->firstBlock->size = totalSize - sizeof(MemoryBlock);pool->firstBlock->prev = NULL;pool->firstBlock->next = NULL;
}// 从内存池中分配内存
void* memoryPoolAllocate(MemoryPool* pool, size_t size)
{MemoryBlock* currentBlock = pool->firstBlock;while (currentBlock != NULL) {// 计算对齐后的内存块大小size_t alignedSize = (size + sizeof(MemoryBlock) - 1) / sizeof(MemoryBlock) * sizeof(MemoryBlock);// 查找第一个满足大小的内存块if (currentBlock->size >= alignedSize) {// 如果内存块过大,将剩余部分分割成新的内存块if (currentBlock->size > alignedSize + sizeof(MemoryBlock)) {MemoryBlock* newBlock = (MemoryBlock*)((uint8_t*)currentBlock + alignedSize + sizeof(MemoryBlock));newBlock->size = currentBlock->size - alignedSize - sizeof(MemoryBlock);newBlock->prev = currentBlock;newBlock->next = currentBlock->next;if (currentBlock->next != NULL) {currentBlock->next->prev = newBlock;}currentBlock->next = newBlock;}// 更新当前内存块的大小currentBlock->size = alignedSize;// 返回分配的内存块地址return (void*)((uint8_t*)currentBlock + sizeof(MemoryBlock));}currentBlock = currentBlock->next;}// 没有合适大小的内存块可供分配return NULL;
}// 释放内存池中的内存
void memoryPoolFree(MemoryPool* pool, void* ptr)
{if (ptr == NULL) {return;}MemoryBlock* block = (MemoryBlock*)((uint8_t*)ptr - sizeof(MemoryBlock));// 合并相邻的空闲内存块if (block->prev != NULL && block->prev->size > 0) {block->prev->next = block->next;block->prev->size += block->size + sizeof(MemoryBlock);block = block->prev;}if (block->next != NULL && block->next->size > 0) {block->size += block->next->size + sizeof(MemoryBlock);block->next = block->next->next;if (block->next != NULL) {block->next->prev = block;}}
}// 释放内存池
void memoryPoolDestroy(MemoryPool* pool)
{free(pool->firstBlock);pool->firstBlock = NULL;pool->totalSize = 0;
}int main(void)
{MemoryPool pool;size_t totalSize = 1024;memoryPoolInit(&pool, totalSize);// 使用内存池分配和释放内存void* ptr1 = memoryPoolAllocate(&pool, 128);void* ptr2 = memoryPoolAllocate(&pool, 256);memoryPoolFree(&pool, ptr1);void* ptr3 = memoryPoolAllocate(&pool, 64);// 在程序结束时释放内存池memoryPoolDestroy(&pool);return 0;
}
科普知识
在计算机编程中还有其他类型的池,它们用于管理不同类型的资源。以下是一些常见的池类型:
-
对象池(Object Pool):用于管理对象的池。对象池预先分配一组对象,并在需要时分配和回收对象,以提高性能。对象池通常用于管理具有复杂构造函数或频繁创建销毁的对象,例如线程池中的工作线程对象。
-
连接池(Connection Pool):用于管理数据库连接、网络连接或其他类型的资源连接的池。连接池预先创建一组连接,以减少连接的创建和销毁开销,并提高系统的响应速度和性能。
-
线程池(Thread Pool):用于管理线程的池。线程池预先创建一组线程,并在需要时分配任务给空闲线程执行,以减少线程创建和销毁的开销,并提高系统的并发性能。
-
缓冲池(Buffer Pool):用于管理缓冲区的池。缓冲池预先分配一组缓冲区,并在需要时分配给请求者,以减少内存分配和释放的开销,并提高系统的内存使用效率。
-
资源池(Resource Pool):用于管理各种类型的资源的池。资源池可以是一个通用的池,用于管理不同类型的资源,例如文件句柄、内存块、套接字等。资源池可以帮助减少资源的创建和销毁开销,提高系统的性能和可伸缩性。
这些池类型都遵循相似的原理,即预先分配一定数量的资源,并在需要时分配给请求者使用,以减少资源的创建和销毁开销,并提高系统的性能和可伸缩性。具体选择何种类型的池取决于应用程序的需求和场景。