c语言手撕内存池组件

news/2024/12/22 2:56:00/

内存池是什么?

        内存池(Memory Pool)是一种内存管理技术,它预先分配一大块内存,然后将其分成多个固定大小的小块。这些小块被组织起来,用于程序在运行期间频繁进行的内存分配和释放操作。内存池通过创建一个“池子”来管理这些小块,以便在需要时快速分配和回收内存,而不需要每次都调用系统的内存分配函数(如 malloc()free())。

        内存池的基本概念是分配一次,重复使用。通过预先分配一大块内存,程序可以在需要时从这个预先分配的内存中快速获取内存块,并在不使用时归还给池子,从而减少频繁的分配和释放操作。
 

使用内存池有什么好处?

  1. 提高性能

            系统的内存分配函数(如 malloc() 和 free())在操作系统级别会涉及复杂的管理操作,尤其是在高频率分配和释放内存时,开销可能很大。
            内存池通过提前分配和复用内存块,减少了频繁的系统调用,从而显著提高性能。特别是在实时系统或需要处理大量小对象的系统中,内存池的性能提升尤为显著。 
  2. 减少内存碎片

            当使用系统的内存分配函数时,如果程序频繁分配和释放不同大小的内存块,可能会导致内存碎片化,即分散的小块可用内存,无法被有效利用。

            内存池通常管理的是大小固定的内存块,因此不会产生内存碎片问题。
  3. 防止内存泄漏

            在某些情况下,内存池可以帮助减少内存泄漏的风险。因为内存池的内存块是固定的,开发者不需要担心忘记释放特定的内存块,只需要在适当的时候释放整个内存池。

        在不同的业务场景下内存池通常也都不一样,在初学内存池阶段,我们实现一个固定块的内存池(在内存池里分配大小一样的小块)。下边是实现过程:

 

        如果释放某个内存块以后,我们下一个可以分配的内存块应该指向刚刚释放的那个内存块,问题是怎么找到它呢?可以通过二级指针实现链表,使每个小内存块的前边存放下一个可以分配的内存块的地址。

函数实现:

#include <stdio.h>
#include <stdlib.h>// 8K的大小
#define MEM_PAGE_SIZE		8192typedef struct mempool_s {int block_size;//固定小内存块的大小int free_count;//内存池中还能分配的内存块的数量 剩余还有多少块char *free_ptr;//下一个内存块可以分配的地址char *mem;//指向分配的内存池的起始地址  指向整块内存
} mempool_t;//内存池初始化
int mp_init(mempool_t *m, int size) {if (!m) return -1;if (size < 16) size = 16;m->block_size = size;m->mem = (char *)malloc(MEM_PAGE_SIZE);//分配整块内存if (!m->mem) return -1;m->free_ptr = m->mem;m->free_count = MEM_PAGE_SIZE / size; //能够分配固定快的大小int i = 0;//二级指针实现单项链表char *ptr = m->free_ptr;for (i = 0;i < m->free_count;i ++) {*(char **)ptr = ptr + size;ptr += size;}*(char **)ptr = NULL;return 0;
}//内存池销毁
void mp_dest(mempool_t *m) {if (!m || !m->mem) return ;free(m->mem);}//分配
void *mp_alloc(mempool_t *m) {if (!m || m->free_count == 0) return NULL;void *ptr = m->free_ptr;m->free_ptr = *(char **)ptr;m->free_count --;return ptr;
}//释放
void mp_free(mempool_t *m, void *ptr) {*(char **)ptr = m->free_ptr;m->free_ptr = (char *)ptr;m->free_count ++;
}int main() {mempool_t m;//分配大小为64字节的固定块mp_init(&m, 64);void *p1 = mp_alloc(&m);printf("1: mp_alloc: %p\n", p1);void *p2 = mp_alloc(&m);printf("2: mp_alloc: %p\n", p2);void *p3 = mp_alloc(&m);printf("3: mp_alloc: %p\n", p3);void *p4 = mp_alloc(&m);printf("4: mp_alloc: %p\n", p4);mp_free(&m, p2);void *p5 = mp_alloc(&m);printf("5: mp_alloc: %p\n", p5);return 0;
}


http://www.ppmy.cn/news/1533069.html

相关文章

汽车革命下半场AI先锋:广汽为新“智”汽车装配大模型“底盘”

汽车革命的上半场是电动化&#xff0c;下半场是智能化&#xff0c;这是全球汽车产业普遍认同的观点。当前&#xff0c;我国汽车产业已经在电动化上半场取得了显著成效&#xff0c;在下半场智能化的全球战场能否胜出&#xff0c;关键看车企的创新意愿和研发实力。 在2024年9月1…

HarmonyOS 组件

在HarmonyOS中构建页面的最小单元是组件&#xff0c;除了官方提供的组件外我们也可以自定义组件。每一个组件都包含视图、状态、事件、生命周期这几个部分。 声明与使用 在HarmonyOS中声明组件使用的是Component装饰器。然后使用struct关键字构建一个结构&#xff0c;并定义b…

二十个编程语言发展的“拦路虎”

引言 编程语言的发展是信息技术史上的重要篇章&#xff0c;它不仅记录了人类智慧与技术进步的轨迹&#xff0c;更是现代信息技术的基础。然而&#xff0c;在这一过程中&#xff0c;各种挑战如同“拦路虎”一般&#xff0c;考验着程序员们的智慧与创造力。本文将探讨这些挑战如…

IP协议讲解

IP协议 IP协议的本质&#xff1a;提供一种能力&#xff0c;将数据跨网络从A主机传输到B主机 4位版本号(version): 指定IP协议的版本, 对于IPv4来说, 就是4. 4位头部长度(header length): IP头部的长度是多少个32bit, 也就是 length * 4 的字节数. 4bit表示最大 的数字是15, 因…

状态模式原理剖析

《状态模式原理剖析》 状态模式&#xff08;State Pattern&#xff09; 是一种行为设计模式&#xff0c;它允许对象在其内部状态改变时改变其行为。换句话说&#xff0c;当对象状态发生变化时&#xff0c;它的行为也会随之变化。 通过状态模式&#xff0c;可以消除通过 if-else…

Pgsql 数据库操作

pgsql&#xff0c;即PostgreSQL&#xff0c;是一种功能强大的开源对象关系数据库系统。它使用并扩展了SQL语言&#xff0c;使其能够存储复杂的数据结构和执行强大的查询。以下是对pgsql数据库操作的一些详细介绍&#xff1a; 一、基本操作 建立数据库连接 可以使用命令行工具…

在线css像素px到Em的转换器

具体请前往&#xff1a;在线Px转Em工具--将绝对像素(px)长度单位转换为相对长度em

图论(bfs系列)9/30

单源点系列: 一、二进制矩阵中的最短路径 给你一个 n x n 的二进制矩阵 grid 中&#xff0c;返回矩阵中最短 畅通路径 的长度。如果不存在这样的路径&#xff0c;返回 -1 。 二进制矩阵中的 畅通路径 是一条从 左上角 单元格&#xff08;即&#xff0c;(0, 0)&#xff09;到…