IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 基于线程本地存储(TLS)的三层内存池 -> 正文阅读

[数据结构与算法]基于线程本地存储(TLS)的三层内存池

一、TLS简介? ??

? ? ?在一个进程中,所有线程共享同一个地址空间。全局变量和静态变量能够被所有线程访问、修改。通过使用线程本地存储(Thread Local Storage,TLS)能够将数据和执行的特定线程联系起来。TLS是各线程独立的数据存储空间,声明的TLS变量在每个线程都有一个副本,在程序中可以安装相同方式来讨论,且互相不影响。

? ? TLS分为静态的和动态的。静态TLS使用语言本身的关键字定义。C/C++中包括:

1、_thread

2、thread_local

3、_declspec(thread)? //g++/gcc编译器下用不了,主要在visual c++下使用

动态TLS通过调用系统API创建。

二、内存池简介

项目参考tc_malloc,分以下三层。

??

1.Thread Cache

? ? ? ? thread cache是内存池中的第一层缓存,这一层缓存能够解决并发状态下锁竞争的效率问题。线程在这里申请不需要加锁,每一个线程都有自己独立的cache,这也就是这个项目并发高效的地方。为了避免加锁带来的效率,在Thread Cache中使用TLS保存每个线程本地的Thread Cache的指针,这样Thread Cache在申请释放内存是不需要锁的。因为每一个线程都拥有了自己唯一的一个全局变量。

? ? ?申请内存小于64k时在Thread Cache中申请内存,计算size在自由链表中的位置。如果自由链表中有内存对象,则直接从FreeList[i]中Pop一下对象,时间复杂度是O(1),且没有锁竞争。当FreeList[i]中没有对象时,则批量从Central Cache中获取一定数量的对象,插入到自由链表并返回一个对象。

? ? ? ?当释放内存小于64k时将内存释放回Thread Cache,计算size在自由链表中的位置,将对象Push到FreeList[i]。当链表的长度过长,也就是超过一次最大限制数目时则回收一部分内存对象到Central Cache。

?Thread Cache是一个对象数组,数组成员为一个个自由链表。

?2.Central Cache

? ? ?TLS虽然解决了内存碎片的问题,但也导致了内存分配不均衡的问题。当一个线程大量开辟内存再释放的时候,会存储大量无法被其他资源使用的空闲内存资源。为解决这个问题,设计出central cache,使程序能够周期性的回收thread cache中的内存资源,避免一个或多个线程占用大量内存资源,而造成其它线程内存资源不足,让内存资源的分配在多个线程中更均衡。

? ? ? ?central cache是由spanlist组成的数组,其中spanlist是由span组成的双向链表。为了保证全局只有一个central cache,这个类设计成单例模式。Central Cache是存在竞争的,所以在这里取内存对象的时候需要加锁,但是锁的力度可以控制得很小。一个span对象大小是恒定的4K大小(32位下4K 64位下8K ) 但是中心缓存数组每个元素指定了单个span划分成内存块的大小 (比如第一个8bytes 第二个16bytes等等),故他们能挂载的内存块数不一样。

? ? ? ?当Central Cache中没有非空的span时,则将空的span链在一起,向Page Cache申请一个span对象,span对象中是一些以页为单位的内存,切成需要的内存大小,并链接起来,挂到span中。Central Cache的span中有一个_usecount,分配一个对象给Thread Cache,就+_usecount。

? ? ? ? 当Thread Cache过长或者线程销毁,则会将内存释放回Central Cache中的,释放回来时- -_usecount。当_usecount减到0时则表示所有对象都回到了span,则将Span释放回Page Cache,Page Cache中会对前后相邻的空闲页进行合并。由span对象划分出去的内存块和这个span对象是有归属关系的,所以由thread cache归还释放某个内存(比如16bytes)应该归还到central cache的16bytes部分的他所归属的那个span对象上。在Page Cache中维护一个页号到span的映射,当Page Cache给Central Cache分配一个span时,将这个映射更新到unordered_map中去,这样的话在central cache中的span对象下的内存块都是属于某个页的 也就有他的页号,,同一个span切出来的内存块PageID都和span的PageID相同,这样就能很好的找出某个内存块属于哪一个span了。也就能通过unorder_map映射到span的id上,从而找到span,在Thread Cache还给Central Cache时,可以查这个unordered_map找到对应的span。

?3.Page Cache

? ? ??

? ? ???Page Cache可回收上层缓存中空闲的span并合并成更大的span,因此可解决内存碎片的问题。当central cache中无空闲span时也会将大的span切小分配。central cache和page cache中的span不同。?central cache中的span只代表一页 然后被分解成了小的内存块链接而成的链表。page cache中的span是有多页组成分的。

????????当Central Cache向page cache申请内存时,Page Cache先检查对应位置有没有span,如果没有则向更大页寻找一个span,如果找到则分裂成两个。比如:申请的是4page,4page后面没有挂span,则向后面寻找更大的span,假设在10page位置找到一个span,则将10page span分裂为一个4page span和一个6page span。如果找到128 page都没有合适的span,则向系统使用map、brk或者是VirtualAlloc等方式申请128page span挂在自由链表中,再重复1中的过程。然后把这个4页的span对象切成4个一页的span对象 放在central cache中的16bytes位置。可以有四个结点,再把这四个一页的span对象切成需要的内存块大小。这里就是16bytes ,并链接起来,挂到span中。

? ? ? ? 当Thread Cache过长或者线程销毁,则会将内存释放回Central Cache中。比如Thread cache中16bytes部分链表数目已经超出最大限制了,则会把后面再多出来的内存块放到central cache的16bytes部分的他所归属的那个span对象上。此时那个span对象的usecount就减一。当_usecount减到0时则表示所有对象都回到了span,则将Span释放回Page Cache,Page Cache中会依次寻找span的前后相邻pageid的span,看是否可以合并,如果合并继续向前寻找。这样就可以将切小的内存合并收缩成大的span,减少内存碎片。

???????通过VirtualAlloc(Windows环境下是VirtualAlloc,Linux下使用brk或者mmap)直接向系统申请内存时,都是以页为单位的内存,在32位机器下,一页就是4K。所以从0开始每一页的起始地址都是4K的整数倍。将申请到的内存地址右移12位得到相应的页号,同样只需要将地址左移12位即得到每一页的起始地址。

????????假如现在有一个PageID为50的3页的span,有一个PageID为53的6页的span。这两个span就可合并成一个PageID为50的9页的span,然后挂在9页的SpanList上。

Github源码??https://github.com/nanjingu/TLSMemoryPool

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-07-15 16:28:07  更:2021-07-15 16:29:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 9:57:27-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计