跨平台c开发库tbox:内存库使用详解

TBox是一个C语言实现的跨平台开发库,它提供了统一的内存管理机制,包括大块内存池、小块内存池、固定块内存池和字符串内存池。内存管理模型参考了Linux内核,但针对大块内存分配进行了优化,避免了不必要的浪费。此外,TBox支持切换全局内存分配器,如默认分配器、静态内存分配器、原生内存分配器和虚拟内存分配器,以适应不同应用场景的需求。该库还内置了内存检测功能,包括内存泄漏、越界、重叠覆盖和双重释放检测,以确保程序的健壮性。
摘要由CSDN通过智能技术生成

TBOX是一个用c语言实现的跨平台开发库。针对各个平台,封装了统一的接口,简化了各类开发过程中常用操作,使你在开发过程中,更加关注实际应用的开发,而不是把时间浪费在琐碎的接口兼容性上面,并且充分利用了各个平台独有的一些特性进行优化。这个项目的目的,是为了使C开发更加的简单高效。

  • 源码仓库:https://github.com/tboox/tbox
  • 在线文档:https://tboox.io/#/zh-cn/

内存整体架构

TBOX的内存管理模型,参考了linux kernel的内存管理机制,并在其基础上做了一些改进和优化。

内存池架构

大块内存池:large_pool

整个内存分配的最底层,都是基于largepool的大块内存分配池,类似于linux的基于page的分配管理,不过有所不同的是,largepool并没有像linux那样使用buddy算法进行(2^N)*page进行分配,这样如果需要2.1m的内存,需要分配4m的内存块,这样力度太大,非常浪费。

因此largepool内部采用N*page的基于pagesize为最小粒度进行分配,因此每次分配顶多浪费不到一页的空间。

而且如果需要的内存不到整页,剩下的内存也会一并返回给上层,如果上层需要(比如small_pool),可以充分利用这多余的部分内存空间,使得内存利用率达到最优化。

而且根据tbinit实际传入的参数需求,largepool有两种模式:

  1. 直接使用系统内存分配接口将进行大块内存的分配,并用双链维护,这种比较简单,就不多说了。
  2. 在一大块连续内存上进行统一管理,实现内存分配。

具体使用哪种方式,根据应用需求,一般的应用只需要使用方式1就行了,这个时候tbinit传tbnull就行了,如果是嵌入式应用,需要管理有限的一块内存空间,这个时候可以使用方式2, tb_init传入指定内存空间地址和大小。

这里就主要看下方式2的large_pool的内存结构(假设页大小是4KB):

     --------------------------------------------------------------------------
    |                                     data                                 |
     --------------------------------------------------------------------------
                                         |
     --------------------------------------------------------------------------
    | head | 4KB | 16KB | 8KB | 128KB | ... | 32KB |       ...       |  4KB*N  |
     --------------------------------------------------------------------------

由于largepool主要用于大块分配,而超小块的分配在上层smallpool中已经被分流掉了,所以这个应用中,large_pool不会太过频繁的分配,所以碎片量不会太大,为了进一步减少碎片的产生,在free时候都会对下一个邻近的空闲块进行合并。而malloc在分配当前空闲块空间不够的情况下,也会尝试对下一个邻近空闲块进行合并。

由于每个内存块都是邻近挨着的,也没用双链维护,没有内存块,都有个块头,合并过程仅仅只是改动内存块头部的size字段,这样的合并不会影响效率。

由于没像buddy算法那样,用双链维护空闲内存,虽然节省了链表维护的空间和时间,但是每次分配内存都要顺序遍历所有块,来查找空闲的内存,这样的效率实在太低了,为了解决这个问题,large_pool内部针对不同级别的块,进行了预测,每次free或者malloc的时候,如果都会把当前和邻近的空闲快,缓存到对应级别的预测池里面去,具体的分级如下:

     --------------------------------------
    | >0KB :      4KB       | > 0*page     | 
    |-----------------------|--------------
    | >4KB :      8KB       | > 1*page     | 
    |-----------------------|--------------
    | >8KB :    12-16KB     | > 2*page     | 
    |-----------------------|--------------
    | >16KB :   20-32KB     | > 4*page     | 
    |-----------------------|--------------
    | >32KB :   36-64KB     | > 8*page     | 
    |-----------------------|--------------
    | >64KB :   68-128KB    | > 16*page    | 
    |-----------------------|--------------
    | >128KB :  132-256KB   | > 32*page    | 
    |-----------------------|--------------
    | >256KB :  260-512KB   | > 64*page    | 
    |-----------------------|--------------
    | >512KB :  516-1024KB  | > 128*page   | 
    |-----------------------|--------------
    | >1024KB : 1028-...KB  | > 256*page   | 
     --------------------------------------

由于通常不会分配太大块的内存,因此只要能够预测1m内存,就足够,而对于>1m的内存,这里也单独加了一个预测,来应对偶尔的超大块分配,并且使得整体分配流程更加的统一。

如果当前级别的预测块不存在,则会到下一级别的预测块中查找,如果都找不到,才回去遍历整个内存池。

实际测试下,每个块的预测成功基本都在95%以上,也就说大部分情况下,分配效率都是维持在O(1)级别的。

小块内存池:small_pool

小块内存分配池

在上层每次调用malloc进行内存分配的时候,回去判断需要多大的内存,如果这个内存超过或者等于一页,则会直接从largepool进行分配,如果小于一页,则会优先通过smallpool进行分配,small_pool针对小块的内存进行了高速缓存,并优化了空间管理和分配效率。

由于程序大部分情况下,都在使用小块内存,因此smallpool对内存的分配做了很大的分流,使得largepool承受的压力减小,碎片量减少很多,而smallpool内部由于都是由fixedpool来对固定大小的内存进行管理,是不会存在外部碎片的。而小块内存的粒度本身就很小,所以内部碎片量也相当少。

smallpool中的fixedpool,就像是linux kernel中的slub,在smallpool中总共有12级别的fixedpool,每个级别分别管理一种固定大小的内存块,具体级别如下:

     --------------------------------------
    |    fixed pool: 16B    |  1-16B       | 
    |--------------------------------------|
    |    fixed pool: 32B    |  17-32B      |  
    |--------------------------------------|
    |    fixed pool: 64B    |  33-64B      | 
    |--------------------------------------|
    |    fixed pool: 96B*   |  65-96B*     | 
    |--------------------------------------|
    |    fixed pool: 128B   |  97-128B     |  
    |--------------------------------------|
    |    fixed pool: 192B*  |  129-192B*   |  
    |--------------------------------------|
    |    fixed pool: 256B   |  193-256B    |  
    |--------------------------------------|
    |    fixed pool: 384B*  |  257-384B*   |  
    |--------------------------------------|
    |    fixed pool: 512B   |  385-512B    |  
    |--------------------------------------|
    |    fixed pool: 1024B  |  513-1024B   |  
    |--------------------------------------|
    |    fixed pool: 2048B  |  1025-2048B  |  
    |--------------------------------------|
    |    fixed pool: 3072B* |  2049-3072B* |  
     -------------------------------------- 

其中 96B, 192B,384B,3072B并不是按2的整数幂大小,这么做主要是为了更加有效的利用小块内存的空间减少内部碎片。

固定块内存池:fixed_pool

顾名思义,fixedpool就是用来管理固定大小的内存分配的,相当于linux中slub,而fixedpool中又由多个slot组成,每个slot负责一块连续的内存空间,管理部分内存块的管理,类似linux中的slab, 每个slot由双链维护,并且参考linux的管理机制,分为三种slot管理方式:

  1. 当前正在分配的slot
  2. 部分空闲slots链表
  3. 完全full的slots链表

具体结构如下:

    current:
         --------------
        |              |
     --------------    |
    |     slot     |<--
    |--------------|
    ||||||||||||||||  
    |--------------| 
    |              | 
    |--------------| 
    |              | 
    |--------------| 
    ||||||||||||||||  
    |--------------| 
    |||||||||||||||| 
    |---------
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值