概述
在项目上,经常遇到芯片内存不够导致编码困扰问题,在此写个笔录,方便后续查阅。
此示例,考虑了一些额外的功能和边界条件,例如内存分配的对齐、内存池的重用等。这个示例使用了双向链表来管理内存块。
源码如下:
#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):用于管理各种类型的资源的池。资源池可以是一个通用的池,用于管理不同类型的资源,例如文件句柄、内存块、套接字等。资源池可以帮助减少资源的创建和销毁开销,提高系统的性能和可伸缩性。
这些池类型都遵循相似的原理,即预先分配一定数量的资源,并在需要时分配给请求者使用,以减少资源的创建和销毁开销,并提高系统的性能和可伸缩性。具体选择何种类型的池取决于应用程序的需求和场景。