内存池出现原因:内存碎片

  首先我们需要明确, 内存池的目的到底是什么?  首先你要知道的是, 我们每次使用new T来初始化类型T的时候, 其实发生了两步操作,

  1. 一个叫内存分配, 这一步使用的其实不是new而是operator new(也可以认为就是C语言中的malloc), 这一步是直接和操作系统打交道的, 操作系统可能需要经过相对繁琐的过程才能将一块指向空闲内存的指针返回给用户, 所以这也是new比较耗时的一部分,
  2. 而第二步就是使用构造函数初始化该内存, 这是我们比较熟悉的.

   既然内存分配耗时, 那我们很容易想到的就是一次性分配一大块内存, 然后在用户需要的时候再划分其中一部分给用户, 这样的话, 一次分配, 多次使用, 自然而然提高了效率, 而用来管理这所谓的一大块内存的数据结构, 也就是今天我们要说的内存池.

  另外一个好处在于, 频繁地使用new将导致系统内存空间碎片化严重, 容易导致的后果就是很难找到一块连续的大块内存, 造成内存碎片(非连续),空间利用率低.

内碎片是指分配给作业的存储空间中未被利用的部分,外碎片是指系统中无法利用的小存储块。

1.内存申请流程图

  小于等于128k的用第二级分配器;

  大于128k的用第一级分配器

2. 第一级配置器:

  第一级採用malloc、free;

此外,这个配置器提供了当内存配置错误时的处理函数oom*malloc,这个函数会调用*_malloc_alloc_oom_handler()这个错误处理函数,去企图释放内存,然后重新调用malloc分配内存。如此循环,直到分配成功,返回指针(所以再一定程度上提高内存分配成功)。

3. 第二级配置器

  使用自由链表(free-list)技巧。主动将不论什么小额区块的内存需求量上调至8的倍数。如需求30,则上调至32。
    free-list节点结构

union obj
{
union obj * free_list_link; //下一个节点的指针
char client_data[]; //内存首地址
}

有16个free-lists。各自管理大小分别为8、16、24、32、40、48、56、64、72、80、88、96、104、112、120、128 bytes的小额区块。

释放内存

所以最终内存池的思路其实是这样的:

1. 使用allocate向内存池请求size大小的内存空间, 如果需要请求的内存大小大于128bytes, 直接使用malloc.

2. 如果需要的内存大小小于128bytes, allocate根据size找到最适合的自由链表.

  a. 如果链表不为空, 返回第一个node, 链表头改为第二个node.

  b. 如果链表为空, 使用blockAlloc请求分配node.

    x. 如果内存池中有大于一个node的空间, 分配竟可能多的node(但是最多20个), 将一个node返回, 其他的node添加到链表中.

    y. 如果内存池只有一个node的空间, 直接返回给用户.

    z. 若果如果连一个node都没有, 再次向操作系统请求分配内存.

      ①分配成功, 再次进行b过程

      ②分配失败, 循环各个自由链表, 寻找空间

        I. 找到空间, 再次进行过程b

        II. 找不到空间, 抛出异常(代码中并未给出, 只是给出了注释)

3. 用户调用deallocate释放内存空间, 如果要求释放的内存空间大于128bytes, 直接调用free.

4. 否则按照其大小找到合适的自由链表, 并将其插入.

特点其实是这样的 :

1. 刚开始初始化内存池的时候, 其实内存池中并没有内存, 同时所有的自由链表都为空链表.

2. 只有用户第一次向内存池请求内存时, 内存池会依次执行上述过程的 1->2->b->z来完成内存池以及链表的首次填充, 而此时, 其他未使用链表仍然是空的.

3. 所有已经分配的内存在内存池中没有任何记录, 释放与否完全靠程序员自觉.

4. 释放内存时, 如果大于128bytes, 则直接free, 否则加入相应的自由链表中而不是直接返还给操作系统.

参考文章:

https://www.cnblogs.com/zsychanpin/p/6936810.html

https://www.cnblogs.com/nzhl/p/5753728.html

C++ STL内存池的更多相关文章

  1. C++技术问题总结-第8篇 STL内存池是怎么实现的

    STL内存池机制,使用双层级配置器.第一级採用malloc.free,第二级视情况採用不同策略. 这样的机制从heap中要空间,能够解决内存碎片问题. 1.内存申请流程图     简要流程图例如以下. ...

  2. sgi stl内存池实现------源码加翻译

    class __default_alloc_template { enum { unit = 8 };//分配单位 后面直接用8代替 enum { max_bytes = 128 };//最大分配字节 ...

  3. SGI STL中内存池的实现

    最近这两天研究了一下SGI STL中的内存池, 网上对于这一块的讲解很多, 但是要么讲的不完整, 要么讲的不够简单(至少对于我这样的初学者来讲是这样的...), 所以接下来我将把我对于对于SGI ST ...

  4. STL源码分析之内存池

    前言 上一节只分析了第二级配置器是由多个链表来存放相同内存大小, 当没有空间的时候就向内存池索取就行了, 却没有具体分析内存池是怎么保存空间的, 是不是内存池真的有用不完的内存, 本节我们就具体来分析 ...

  5. STL源码剖析——空间配置器Allocator#3 自由链表与内存池

    上节在学习第二级配置器时了解了第二级配置器通过内存池与自由链表来处理小区块内存的申请.但只是对其概念进行点到为止的认识,并未深入探究.这节就来学习一下自由链表的填充和内存池的内存分配机制. refil ...

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

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

  7. C++STL内存管理方法(g++版)

    STL作为C++的经典作品,一直备受人们关注.本文主要介绍STL的内存管理策略. 早期的STL内存管理 第一次接触STL源码是看侯捷先生的<STL源码剖析>,此书通俗易懂,剖析透彻,是极佳 ...

  8. nginx——内存池篇

    nginx--内存池篇 一.内存池概述 内存池是在真正使用内存之前,预先申请分配一定数量的.大小相等(一般情况下)的内存块留作备用.当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续 ...

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

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

随机推荐

  1. vi和vim的使用

    本章内容: vi编辑器简介 vim基本使用 vim使用技巧 一.vim简介 vim是一个全屏幕纯文本编辑器,是vi编辑器的增强版. 二.vim的基本使用 1.vim的工作模式 命令模式:是主要使用快键 ...

  2. 「SNOI2019」通信 分治建图

    根据题意 每个点可以直接与S,T相连 也可以和前面的哨站相连 暴力建边的话 有n2条边 要用分治优化建边: 类似于归并排序 先对每一层分为左半边与右半边 对每一半都拿出来先排序去重后 直接排成一条链建 ...

  3. Java web中文乱码

    1.设置工程的编码方式 window-preferences-general-workspace 改成uef-8 2.设置html的编码方式 <meta http-equiv="Con ...

  4. JDBC下

    存储过程名字前面一定要加一个sp,代表是存储过程 nofilter:没有过滤器,没有参数 )) BEGIN IF sp_name IS NULL OR sp_name='' THEN SELECT * ...

  5. Redis五种数据结构(二)

    Redis数据结构 Redis数据结构介绍 Redis是一种高级的key-value的存储系统,其中value支持五种数据类型. 字符串(String) 哈希(hash) 字符串列表(list) 字符 ...

  6. 【转载】解决繁体、日文游戏乱码的五种方法 转载自:http://tieba.baidu.com/p/488627981

    方法1:转换区域 开始——设置——控制面板——区域和语言选项——分别选择“高级”和“区域选项”标签——在其下拉框中都选择“日语”(或“日本”)(选项有点多,慢慢找)——重启后即可生效. *某影注:日语 ...

  7. Vue学习日记(三)——Vue路由管理vue-router

    前言 为了给读者更好的体验,去理解vue-router和下一篇介绍vuex,决定还是来一个实战教程来带大家更加的去深入理解vue-router,在这之前,读者先自行了解和去官网下载npm和node,附 ...

  8. 压测工具ab的简单使用

    apache benchmark(ab)是一种常见的压测工具,不仅可以对apache进行压测,也可以对nginx,tomcat,IIS等进行压测 安装 如果安装了apache,那么ab已经自带了,不需 ...

  9. python 省略号 三个点...的含义

    总结一下: 1.省略号在python里也是个对象. 2.=...(赋值号后面省略号),给该变量赋值一个default值.具体python的机制我不清楚.应该是在类里面定义好的. 3.: ...(冒号后 ...

  10. HDU 6085 - Rikka with Candies | 2017 Multi-University Training Contest 5

    看了标程的压位,才知道压位也能很容易写- - /* HDU 6085 - Rikka with Candies [ 压位 ] | 2017 Multi-University Training Cont ...