C++ STL内存池
内存池出现原因:内存碎片
首先我们需要明确, 内存池的目的到底是什么? 首先你要知道的是, 我们每次使用new T来初始化类型T的时候, 其实发生了两步操作,
- 一个叫内存分配, 这一步使用的其实不是new而是operator new(也可以认为就是C语言中的malloc), 这一步是直接和操作系统打交道的, 操作系统可能需要经过相对繁琐的过程才能将一块指向空闲内存的指针返回给用户, 所以这也是new比较耗时的一部分,
- 而第二步就是使用构造函数初始化该内存, 这是我们比较熟悉的.
既然内存分配耗时, 那我们很容易想到的就是一次性分配一大块内存, 然后在用户需要的时候再划分其中一部分给用户, 这样的话, 一次分配, 多次使用, 自然而然提高了效率, 而用来管理这所谓的一大块内存的数据结构, 也就是今天我们要说的内存池.
另外一个好处在于, 频繁地使用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内存池的更多相关文章
- C++技术问题总结-第8篇 STL内存池是怎么实现的
STL内存池机制,使用双层级配置器.第一级採用malloc.free,第二级视情况採用不同策略. 这样的机制从heap中要空间,能够解决内存碎片问题. 1.内存申请流程图 简要流程图例如以下. ...
- sgi stl内存池实现------源码加翻译
class __default_alloc_template { enum { unit = 8 };//分配单位 后面直接用8代替 enum { max_bytes = 128 };//最大分配字节 ...
- SGI STL中内存池的实现
最近这两天研究了一下SGI STL中的内存池, 网上对于这一块的讲解很多, 但是要么讲的不完整, 要么讲的不够简单(至少对于我这样的初学者来讲是这样的...), 所以接下来我将把我对于对于SGI ST ...
- STL源码分析之内存池
前言 上一节只分析了第二级配置器是由多个链表来存放相同内存大小, 当没有空间的时候就向内存池索取就行了, 却没有具体分析内存池是怎么保存空间的, 是不是内存池真的有用不完的内存, 本节我们就具体来分析 ...
- STL源码剖析——空间配置器Allocator#3 自由链表与内存池
上节在学习第二级配置器时了解了第二级配置器通过内存池与自由链表来处理小区块内存的申请.但只是对其概念进行点到为止的认识,并未深入探究.这节就来学习一下自由链表的填充和内存池的内存分配机制. refil ...
- 基于C/S架构的3D对战网络游戏C++框架_05搭建系统开发环境与Boost智能指针、内存池初步了解
本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...
- C++STL内存管理方法(g++版)
STL作为C++的经典作品,一直备受人们关注.本文主要介绍STL的内存管理策略. 早期的STL内存管理 第一次接触STL源码是看侯捷先生的<STL源码剖析>,此书通俗易懂,剖析透彻,是极佳 ...
- nginx——内存池篇
nginx--内存池篇 一.内存池概述 内存池是在真正使用内存之前,预先申请分配一定数量的.大小相等(一般情况下)的内存块留作备用.当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续 ...
- Ogre内存池的使用和说明
大家可能会遇到一些Ogre中的内存分配的方面问题,我对这个总结了一下内存分配的方面资料. Ogre在1.7版本后,统一了内存分配策略,提供了内存是否泄漏的跟踪和内存池等比较方便开发的一些策略,目前提供 ...
随机推荐
- 多线程模块的condition对象
Python提供的Condition对象提供了对复杂线程同步问题的支持.Condition被称为条件变量,除了提供与Lock类似的acquire和release方法外,还提供了wait和notify方 ...
- 使用Mysql-magic获取Mysql账户密码
版权声明:本文为博主原创文章,欢迎转载,转载请注明原文超链接https://www.cnblogs.com/zerotrust/p/10846530.html 本文仅限于技术讨论与分享,严禁用于非法用 ...
- All-in-One Office,不容错过的办公插件
WPS Office是由金山自主研发的一款办公软件套装,具备办公软件最常用的文字.表格.演示等多种功能. 这款国产办公软件不仅免费,而且具有内存小.海量模板.兼容性强.操作更加符合中国人使用习惯等 ...
- url传参特殊字符问题(+、%、#等)
这样的话,你传的大多数带特殊符号的参数,都能在后台拿到,但是, url中可能用到的特殊字符及在url中的经过编码后的值:(此表格借鉴) 字符 特殊字符的含义 URL编码 # 用来标志特定的文档 ...
- HDU 6046 - hash | 2017 Multi-University Training Contest 2
思路来自题解和一些博客 最麻烦的是样例没啥用- - /* HDU 6046 - hash [ hash,鸽巢 ] | 2017 Multi-University Training Contest 2 ...
- 查看nginx服务器状态
编译安装时使用--with-http_stub_status_module开启状态页面模块 [root@proxy ~]# yum -y install gcc pcre-devel openssl- ...
- 【leetcode】1295. Find Numbers with Even Number of Digits
题目如下: Given an array nums of integers, return how many of them contain an even number of digits. Exa ...
- mysql: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
https://www.cnblogs.com/jpfss/p/9734487.html (mysql.sock错误解决方案)
- 封装Vue组件的一些技巧
封装Vue组件的一些技巧 本文同步在个人博客shymean.com上,欢迎关注 写Vue有很长一段时间了,除了常规的业务开发之外,也应该思考和反思一下封装组件的正确方式.以弹窗组件为例,一种实现是在需 ...
- ZOJ - 4114 Flipping Game
ZOJ - 4114 Flipping Game 题目大意:给出两个串s,t,n个灯泡的序列,1代表开着,0代表关着,一共操作k轮,每轮改变m个灯泡的状态,问最终能把s串变成t串的方案数. 坤神题解. ...