项目整体框架:从随笔中 “破土而出”

💓博主CSDN主页:Am心若依旧💓

专栏分类项目记录

🚚代码仓库:青酒余成🚚

🌹关注我🫵带你学更多的知识
  🔝🔝

1.前言

由于本项目是模拟学习tcmalloc的优秀的思想以及巧妙的结构,所
以本项目只会把源项目的精华部分拿出来学习,请大家耐心看完

本章重点:

本篇文章着重讲解本项目的大致框架结构,以及每一层小结构的内
部的部分细节,这篇文章不会有很多
的代码演示,但至关重要!!!

2.内存池整体结构预览

首先,我们采用了三层缓存结构来实现不同的功能,每一层结构都互相紧密联系:

三层结构大致如下:

  • ThreadCache(线程缓存结构)

线程缓存结构主要是每个线程单独共享的,当线程要申请内存时,就去对应的ThreadCache里面申请,释放也还给对应的ThreadCache里面。只能用于小于256KB的内存分配.整个线程缓存结构是不用加锁的

  • CentralCache(中心缓存结构)

中心缓存是所有线程所共享的,thread cache是按需从central cache中获取对象。central cache会在合适的时机回收thread cache中的对象,避免一个线程占用了太多的内存,而其他线程的内存吃紧,达到内存分配在多个线程中更均衡的按需调度的目的。central cache是存在竞争的,所以从这里取内存对象是需要加锁(几个线程的ThreadCache同时没有内存空间,需要在CentralCache里面获取),这里用的是桶锁,其次只有线程对应的thread cache没有内存时才会找central cache,所以这里竞争不会很激烈

  • PageCache(页缓存结构)

页缓存是在central cache缓存上面的一层缓存,存储的内存是以页为单位存储及分配的,central cache没有内存对象时,从page cache分配出一定数量的page,并切割成定长大小的小块内存,分配给central cache。当一个span的几个跨度页的对象都回收以后,page cache会回收central cache满足条件的span对象,并且合并相邻的页,组成更大的页,缓解内存碎片的问题

 看到这里,可能大家对应第一层略微还有点理解,但是对于第二、第三层可能就不太理解了,但是没有关系,在后面都会一  一的给大家介绍。

3.线程缓存结构介绍

线程缓存结构实际上是一个哈希桶,数组的下标代表这个桶中存放的小
块内存的字节数是多少,桶中存放小块儿内存,就是定长池中的自由链表。

 申请内存的步骤:

申请内存时,比如申请8字节大小内存,会先去8字节对应的哈希桶中查看有
没有小块儿内存,如果有,则直接返回给外部,若对应的桶无小块儿内存,再去
中心缓存中拿内存!

释放内存的步骤:

释放内存时,比如释放的内存大小是24字节,那么当有返回来的空间时,就会挂
在16字节对应的哈希桶中,当满足某种条件时,线程缓存中的小块儿内存会还
给中心缓存(最开始的内存是中心缓存给的)

4.中心缓存结构介绍

中心缓存结构本质也是一个哈希桶,并且它的数组下标和线程缓存是相同
的,但是哈希桶中存储的内容不同,中心缓存中存储的是一个span结构,span
就是一个结构体,它负责管理大块内存。

对span的简单介绍:

假设一页内存是8KB,那么span管理的大块儿内存实际上是大页内存,可能是一页,两页内存,
这个大页内存会被切分为小块儿的内存,8KB对应的哈希桶中会切分为8字节的小块儿内存,这样可以很方便的将小块儿内存分配给线程缓存!

Span的来源:

中心缓存的span实际上是由页缓存分配的,并且在一个span满足某种条件时,会
把此span还给页缓存,并且span是一个双链表结构,一个哈希桶桶中可能有多个
span,下面是span的大致成员变量:

//管理多个连续页的大块内存跨度结构,centralcache的哈希桶中链接的就是这种结构
class SpanData
{
public:
	size_t _n = 0;//此span中的页数
	SpanData* _next = nullptr;
	SpanData* _prev = nullptr;
	size_t _useCount = 0;//span中切分好的小对象有几个被使用了
	void* _freeList = nullptr;//切分好的小块内存的自由链表
};

5.页缓存结构介绍

页缓存结构的本质也是一个哈希桶,但它的数组下标含义与前两层不同,
它的下标代表这个哈希桶中存放的span一共有多少页内存!

Span的来源与去向:

页缓存中的span和中心缓存中的span结构体是一样的,

但页缓存中的span是直接从系统中申请的大块儿空间,

并且这个span会直接分配给中心缓存去切分为小块儿内存后被使用

页缓存申请的基本步骤:

当线程缓存的哈希桶中没有小块儿内存时,并且中心缓存对应的哈希桶中页没有span了,这时会来页缓存申请span回去做切分使用,假设申请的span是5页大小,那么就会去页缓存的五号桶中查看是否有span,若有span就直接返回。若没有span,则需要去6到128号桶中寻找是否存在span,假设50号桶中有span,那么会将这个50页的大span切分为一个5页的小span和一个45页的大span,再将这个5页的span返回给中心缓存,这个45页的span重新挂到页缓存的45号桶中!假如6到128号桶都没有span,则会向系统申请一个128页的大块儿空间,再来切分成小span返回

6.总结

这整个三层结构的设计是十分巧妙的,
在线程缓存中是不需要加锁的,因为每
个线程独享这个结构,这也是这个项目
比较快的原因之一,在中心缓存中也不
需要完全加锁,而是使用桶锁,只有当不同
的线程进入到同一个桶时才会有锁互斥!

一起学习吧,越学习越能够感觉到gogle大佬的牛逼思想,只有通过学习这些高级的思想,我们才能够变得越来越厉害。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值