1. 序言

对于程序开发人员来说,会经常听到这种“池”的概念,例如“进程池”,“线程池”,“内存池”等,虽然很多时没有吃过肉,但是总是见到它跑。上周由于需要性能调优,因此就尝试使用内存池的方式来分配空间,从而提供效率的问题。

网上有各种很优秀的通用的内存池的实现代码:可以调整内存池大小,支持多种大小的内存池,支持调整分配空间大小等等,这种实现是比较完整的实现,但是它针对整个工程或者项目而言是很好的选择。如果我们的需求很是单一,只是想提高某一特定的性能,需要的空间也是固定大小,那么我们就没有必要使用那么优秀复杂的内存池实现。以一言蔽之,最好的不一定适合自己,适合自己的才是最好的

下面介绍一种最简单的内存池的实现:

2. 数据结构

通过上述的数据结构,基本便可以得知内存池的实现方式了,下面做一个简单的说明:

这个简单的内存池实现中,我定义了两种数据结构:

  • 内存池结构信息
struct memoryPool{
int current;
int used_count;
int used[MEMORY_POOL_SIZE];
memoryNode_t memPool[MEMORY_POOL_SIZE];/*MEMORY_POOL_SIZE=64*/
};
  • 内存节点结构
typedef struct node{
int data;
}memoryNode_t;

该数据结构可根据需求自己实现。

内存池实现逻辑如下:

  • 定义一个内存池结构信息的全局变量struct memoryPool *G_memPool
  • 通过内存池初始化函数来构建内存池结构,并初始化内存池参数信息
  • 调用实现的malloc函数来分配空间
    • 通过current的值和used[]数组的值来找到未使用的元素,设置used[]的值,然后返回给申请者;

      • 遍历时,先遍历current-----末尾的空间;如果没有找到合适的,再编译开始—current空间的元素;如果两者都没有找到空闲内存,则分配失败。
  • 调用实现的free函数来释放空间
    • 根据释放的内存地址信息,找到对应的数组下标,然后清空used[i]的值即可。

3. 代码实现

/*************************************************************************
> File Name: simpleMemoryPool.c
> Author: Toney Sun
> Mail: vip_12048020481075266@162048.com
> Created Time: 2020年07月18日 星期六 08时40分51秒
************************************************************************/ #include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h> typedef struct node{
int data;
}memoryNode_t; #define MEMORY_POOL_SIZE 2048 struct memoryPool{
int current;
int used_count;
int used[MEMORY_POOL_SIZE];
memoryNode_t memPool[MEMORY_POOL_SIZE];
}; struct memoryPool *G_memPool = NULL; int memoryPool_init()
{
G_memPool = (struct memoryPool *)malloc(sizeof(struct memoryPool));
if(NULL == G_memPool){
printf("[ %s:%d ]: malloc error\n", __func__, __LINE__);
return -1;
}
memset(G_memPool, 0 , sizeof(struct memoryPool));
return 0;
} void memoryPool_show()
{
int i = 0;
int used = 0;
for( ; i<MEMORY_POOL_SIZE ; i++){
if(G_memPool->used[i]){
used ++ ;
}
}
return;
} memoryNode_t *memoryPool_malloc()
{
int i = G_memPool->current;
for( ; i<MEMORY_POOL_SIZE ; i++){
if(G_memPool->used[i])
continue;
G_memPool->used[i] = 1;
G_memPool->current += 1;
G_memPool->used_count += 1;
if(G_memPool->current == MEMORY_POOL_SIZE){
G_memPool->current = 0;
}
return &(G_memPool->memPool[i]);
} for(i = 0; i < G_memPool->current; i++){
if(G_memPool->used[i])
continue;
G_memPool->used[i] = 1;
G_memPool->used_count += 1;
return &(G_memPool->memPool[i]);
}
printf("[ %s:%d ]: FULL memory Pool!!!\n", __func__, __LINE__);
return NULL;
} int memoryPool_free(memoryNode_t * node)
{
if(!node){
return 0;
} int index = node - G_memPool->memPool;/*非 char *,不用除以sizeof(memoryNode_t) */
if(index < 0 || index >= MEMORY_POOL_SIZE)
return -1;
if(G_memPool->used[index]==0){
return -2;
}
G_memPool->used[index] = 0;
G_memPool->used_count -= 1;
return 0;
} int memoryPool_destroy()
{
if(!G_memPool){
free(G_memPool);
}
return 0;
} /*********************************************
* demo
*********************************************/
#include <time.h> int memPool_demo()
{
int i = 0;
memoryNode_t *node[2048]={NULL};
for(i=0;i<2048;i++)
{
node[i] = memoryPool_malloc();
if(NULL == node[i]){
printf("[ %s:%d ]: i= %d malloc error\n", __func__, __LINE__, i);
return -1;
}
node[i]->data = i;
}
for(i=0;i<2048;i++)
{
//printf("[ %s:%d ]: node[%d]=%d\n", __func__, __LINE__, i, node[i]->data);
} for(i=0;i<2048;i++)
{
if(node[i]){
int ret = memoryPool_free(node[i]);
if(ret != 0){
printf("MemoryPool free error\n");
return -1;
}
}
}
return 0;
} int commonProc()
{
int i = 0;
memoryNode_t *node[2048]={NULL}; for(i=0;i<2048;i++)
{
node[i] = (memoryNode_t *)malloc(sizeof(memoryNode_t));
if(NULL == node[i]){
printf("[ %s:%d ]: i= %d malloc error\n", __func__, __LINE__, i);
return -1;
}
node[i]->data = i;
}
for(i=0;i<2048;i++)
{
//printf("[ %s:%d ]: node[%d]=%d\n", __func__, __LINE__, i, node[i]->data);
} for(i=0;i<2048;i++)
{
if(node[i]){
free(node[i]);
}
}
return 0;
} int main(int argc, char **argv)
{
int cnt=500000;
clock_t start, end;
start = end = 0;
start = clock();
memoryPool_init(); while(cnt--)
memPool_demo(); memoryPool_destroy();
end = clock();
printf("Memory Pool duration ; %f\n", (double)(end - start)/CLOCKS_PER_SEC); cnt=500000;
start = end = 0;
start = clock();
while(cnt--) commonProc();
end = clock();
printf("Common Process duration ; %f\n", (double)(end - start)/CLOCKS_PER_SEC); }

测试结果如下:

root@ubantu:/mnt/hgfs/em嵌入式学习记录/6. 内存池/simpleMemoryPool# gcc simpleMemoryPool.c
root@ubantu:/mnt/hgfs/em嵌入式学习记录/6. 内存池/simpleMemoryPool# ./a.out
Memory Pool duration ; 10.462097
Common Process duration ; 13.642470
root@ubantu:/mnt/hgfs/em嵌入式学习记录/6. 内存池/simpleMemoryPool#

从测试结果上可以看出,内存池在速度上是比每次分配释放的要快的。要知道现在的网络环境即将步入5G时代,在大吞吐量的网络环境中这种差异还是很大的。

4. 总结

这是针对某一特定功能的很简单的内存池实现,不考虑程序的通用性,因此不能满足绝大多数的需求。还是那句话,适合自己的才是最好的。麻雀虽小,五脏俱全,通过这个简单的实现可以初步了解内存池的实现原理,后续再整理一份详细的,全面的内存池实现框架。

简单内存池的C实现的更多相关文章

  1. C++实现简单的内存池

    多进程编程多用在并发服务器的编写上,当收到一个请求时,服务器新建一个进程处理请求,同时继续监听.为了提高响应速度,服务器采用进程池的方法,在初始化阶段创建一个进程池,池中有许多预创建的进程,当请求到达 ...

  2. 基于C/S架构的3D对战网络游戏C++框架 _05搭建系统开发环境与Boost智能指针、内存池初步了解

    本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...

  3. 【uTenux实验】内存池管理(固定内存池和可变内存池)

    1.固定内存池管理实验 内存管理是操作系统的一个基础功能.uTenux的内存池管理函数提供了基于软件的内存池管理和内存块分配管理.uTenux的内存池有固定大小的内存池和大小可变的内存池之分,它们被看 ...

  4. 对象池与.net—从一个内存池实现说起

    本来想写篇关于System.Collections.Immutable中提供的ImmutableList里一些实现细节来着,结果一时想不起来源码在哪里--为什么会变成这样呢--第一次有了想写分析的源码 ...

  5. nginx源码学习----内存池

    最近在进行监控平台的设计,之前一直觉得C/C++中最棘手的部分是内存的管理上,远不止new/delete.malloc/free这么简单.随着代码量的递增,程序结构复杂度的提高.各种内存方面的问题悄然 ...

  6. nginx源码分析—内存池结构ngx_pool_t及内存管理

    Content 0. 序 1. 内存池结构 1.1 ngx_pool_t结构 1.2 其他相关结构 1.3 ngx_pool_t的逻辑结构 2. 内存池操作 2.1 创建内存池 2.2 销毁内存池 2 ...

  7. Ogre内存池的使用和说明

    大家可能会遇到一些Ogre中的内存分配的方面问题,我对这个总结了一下内存分配的方面资料. Ogre在1.7版本后,统一了内存分配策略,提供了内存是否泄漏的跟踪和内存池等比较方便开发的一些策略,目前提供 ...

  8. 定长内存池之BOOST::pool

    内存池可有效降低动态申请内存的次数,减少与内核态的交互,提升系统性能,减少内存碎片,增加内存空间使用率,避免内存泄漏的可能性,这么多的优点,没有理由不在系统中使用该技术. 内存池分类: 1.      ...

  9. NGINX(二)内存池

    ngxin中为了加快内存分配的速度,引入了内存池, 大块申请, 减少分配次数, 小块分割, 极大的提高了内存申请速度, 另外一个用途就是省去了很多内存管理的任务,因为这里没有提供内存释放的功能,也就是 ...

随机推荐

  1. 快速上手 Rook,入门云原生存储编排

    Rook 是一个开源 cloud-native storage orchestrator(云原生存储编排器),为各种存储解决方案提供平台.框架和支持,以与云原生环境进行原生集成. Rook 将存储软件 ...

  2. openssl not found 离线安装的openssl问题

    离线安装问题 正常我们在Linux中按照 nginx的openssl依赖都是通过 yum来安装的,但是由于一些特殊的服务器公司不让服务器连接互联网,所以就导致我们必须通过离线方式来进行安装,但是我们离 ...

  3. Python 列表解析式竟然支持异步?

    PEP原文:https://www.python.org/dev/peps/pep-0530 PEP标题:PEP 530 -- Asynchronous Comprehensions PEP作者:Yu ...

  4. 线程优先级_priority

    线程优先级_priority Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行 线程的优先级用数字表示,范围从1~10 Thread. ...

  5. 2021 年 iOS 应用程序开发七种最佳语言

    移动应用程序现在几乎是每个在线业务的必备品.最新的 StatCounter 数据显示,多达56% 的在线连接是通过移动设备建立的,这使它们高于平板电脑和计算机.更重要的是,同一个消息来源说,其中27% ...

  6. STM32—4线SPI驱动SSD1306 OLED

    文章目录 一.OLED简介 二.驱动SSD1306所需知识 1.引脚介绍 2.通信时序 3.显存GRAM 4.字库 5.SSD1306基本命令 三.代码讲解 1.相关引脚配置 2.模拟SPI通信 3. ...

  7. 本文详细阐述如何用C#创建COM组件,并能用VC6.0等调用。

    本文详细阐述如何用C#创建COM组件,并能用VC6.0等调用. 附:本文适用任何VS系列工具. 在用C#创建COM组件时,一定要记住以下几点: 1.所要导出的类必须为公有: 2.所有属性.方法也必须为 ...

  8. 【开发工具】idea常用配置

    1. 设置鼠标滚轮修改字体大小 我们可以勾选此设置后,增加Ctrl + 鼠标滚轮 快捷键来控制代码字体大小显示. 2. 设置鼠标悬浮提示  3. 设置自动导包功能 Add unambiguous im ...

  9. uwp 动画之圆的放大与缩小

    xml code --------------------------------------------------- <Page x:Class="MyApp.MainPage&q ...

  10. JSP页面添加当前时间

    JSP页面添加当前时间 一.时间格式化 1.引入标签 <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/js ...