【C++】STL 之空间配置器 | STL 总结

👉什么是空间配置器👈

空间配置器,顾名思义就是为各个容器高效的管理空间(空间的申请与回收)的,在默默地工作。虽然在常规使用STL时,可能用不到它,但站在学习研究的角度,学习它的实现原理对我们有很大的帮助。注:空间配置器是内存池。
在这里插入图片描述
直接向堆区申请内存的有 Windows 下的 VirtualAlloc 和 Linux 下的 brk,这个一般不符合我们的需求。而 malloc 是向堆区申请内存的函数,也本质是一个内存池,可用于整个程序的内存管理。STL 的空间配置器也是内存池,其是专门服务 STL 容器的内存管理,以提高效率。

👉为什么需要空间配置器👈

前面在模拟实现 vector、list、map、unordered_map 等容器时,所有需要空间的地方都是通过 new 申请的,虽然代码可以正常运行,但是有以下不足之处:

  • 空间申请与释放需要用户自己管理,容易造成内存泄漏
  • 频繁向系统申请小块内存块,容易造成内存碎片
  • 频繁向系统申请小块内存,影响程序运行效率
  • 直接使用 malloc 与 new 进行申请,每块空间前有额外空间浪费
  • 申请空间失败怎么应对
  • 代码结构比较混乱,代码复用率不高
  • 未考虑线程安全问题

👉SGI-STL 空间配置器实现原理👈

以上提到的几点不足之处,最主要还是:**频繁向系统申请小块内存造成的。**那什么才算是小块内存?SGI-STL 以 128 字节作为小块内存与大块内存的分界线,将空间配置器其分为两级结构,一级空间配置器处理大块内存,二级空间配置器处理小块内存。
在这里插入图片描述

一级空间配置器

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

二级空间配置器

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
如果申请的内存字节数小于 128 时,就走二级空间配置器。首先,看看该大小的内存对应的桶中有没有内存,如果有就直接返回;如果没有,就去调用 malloc 申请大块内存,并将大块内存切分成小块内存头插到对应的桶中。如果多次申请该大小的内存时,就能够提高效率了。

free_list 的桶和哈希桶的区别:哈希桶挂的是节点,这些节点都是一样的;free_list 的桶挂的是内存,不同的桶挂的内存大小是不一样的。因为一个指针是4个字节 或 8 个字节,而我们只需要让内存的头 4 个或 8 个字节指向下一个内存的地址,最后一块内存的头 4 个或 8 个内存指向空。
在这里插入图片描述
假设现在要申请 40 个字节,发现桶没有,就去看大块内存够不够 40 个字节。假设没有且再去用 malloc 申请大块内存也失败了,这时候就会去看后面的桶有没有比 40 大的内存,如果有,就将该内存切分成 40 大小的内存和更小的内存,并将该内存挂在对应的桶上。如果还是没有,那么就抛异常。
在这里插入图片描述
STL 的空间配置器是专门服务容器的,假设 list 的一个节点大小为 12 个字节,set 的一个节点为 16 字节。假设 list 尾插了 15 次,那么它就使用了 15 个 16 字节大小的内存(大块内存可以被切分成 20 个 所需空间的小内存)。那么现在还是剩下 5 个 16 字节大小的内存,此时 set 开始 insert,那么这 5 个内存就可以被 set 使用。假设 set insert 3 次后,list 析构了并将其内存挂回了 free_list 的桶上,那么这些内存也就可以被 set 所使用。这也是空间配置器提高效率的做法。

一个进程里面应该只有一个空间配置器,所以空间配置器可以设计成单例模式的类。SGI 的 STL 空间配置器是通过静态成员来间接实现单例模式的。

👉空间配置器的优势👈

  1. 频繁申请小块内存时,效率高(memory 头文件中的 allocator 就是 STL 的空间配置器,可以和 malloc 进行效率对比)。
  2. 一定程度上缓解了内存碎片的问题,内存碎片分为外碎片和内碎片
  • 外碎片问题是由频繁向系统申请小块内存造成的。频繁向系统小块内存会造成有足够的内存,但是不连续,无法申请大块的内存。
  • 内碎片问题是实际申请到的内存多于所需的内存,而多出来的内存用户也无法使用。内存块按一定的对齐规则挂起来管理,就会导致内碎片问题。比如:list 的一个节点需要 12 个字节,系统给了用户 16 个字节,多出来的 4 个字节用户也无法使用。内存池一般都会有内碎片问题,内碎片问题不是很严重。

malloc 和 内存池的对比

注:以下实现的定长内存池是高并发内存池项目中的组件,以后会详细讲解!定长内存池的空间是不释放的,因为大块内存已经被切分了好多次,无法正确释放。但是只要进程是正常结束的,也不要造成内存泄漏问题。进程正常结束,操作系统会回收内存。
在这里插入图片描述

// ObjectPool是针对某一类对象的定长内存池
#pragma once

#include <iostream>
#include <vector>
#include <time.h>
// 工程项目中不要将std整个命名空间展开,避免命名污染
using std::cout;
using std::endl;

// 操作系统的控制,如果是Windows系统则包含windows
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值