ptmalloc - 小块内存管理初探

本文探讨了ptmalloc中小块内存(≤64字节)的管理方式,通过使用双链表缓存和最佳适配算法,实现了内存的有效分配与回收。

ptmalloc - 小块内存管理初探


停更了两个月,一方面是转去了django开发,需要时间去学习,另一方面,好游戏比较多。

不过放心,现在开始专心开车,带你游历glibc ptmalloc簇函数实现。

前面已经写过几篇文章了,算是初探,也没有特别的深入到内存块管理方式,不过,基本的感性认知已经是有了,例如知道用到了sbrk,mmap等。

要开车了,坐稳吧。

要点


  • Ptmalloc里面的内存管理
  • 预备知识
  • 小块内存初探
  • 结尾

Ptmalloc里面的内存管理


是不是好奇为啥没有了用例,这一章是纯代码解释,不好放用例,放了用例开展更多的代码,车速不是你们能够承受的。

按照glibc/malloc/malloc.c里面的注释,写了四种内存管理算法,我大概说下

  1. 对于大内存(大于512byte)的申请,就是用 最佳适用申请器 加上FIFO
  2. 小块的(小于等于64byte),就是有个池缓存着块
  3. 介于中间的,希望结合大小块管理方式
  4. 大于等于128KB的,就是之前那篇《第一次申请与释放大内存》

我大概翻译了下,不完全准确,也别纠结,个人觉得给你原文你也不一定能知道究竟具体是什么。拉上安全带吧,上代码了。今天就初探下第三点。

预备知识


第一点, struct malloc_chunk 相关的结构,在《第一次申请小内存》里面说过了,不记得么,想我重新说么

自己看去

第二点,起码要知道什么是链表,不懂我教你啊,学费一小时1k,刚好缺钱买键盘

第三点,应该没有了,不过要凑个三,处女座嘛

小块内存初探


代码

代码不多,先全部贴上来,老规矩,跟主题无关的代码就直接砍了

static void *
_int_malloc (mstate av, size_t bytes)
{

    ....

    // [0]
    if (in_smallbin_range (nb)) {
        idx = smallbin_index (nb);
        bin = bin_at (av, idx);

        // [1]
        if ((victim = last (bin)) != bin) {
            // [2]
            if (victim == 0) {
                malloc_consolidate (av);

            // [3]
            } else {
                bck = victim->bk;

                if (__glibc_unlikely (bck->fd != victim))
                {
                    errstr = "malloc(): smallbin double linked list corrupted";
                    goto errout;
                }
                set_inuse_bit_at_offset (victim, nb);
                bin->bk = bck;
                bck->fd = bin;

                void *p = chunk2mem (victim);
                alloc_perturb (p, bytes);
                return p;
            }
        }
    }

    ....

[0]

三句代码,就是三个宏

#define MIN_LARGE_SIZE 1024

#define in_smallbin_range(sz)  \
  ((unsigned long) (sz) < (unsigned long) MIN_LARGE_SIZE)

#define smallbin_index(sz) ((sz) >> 4)

#define bin_at(m, i) \
    (mbinptr) (((char *) &((m)->bins[((i) - 1) * 2])) - \
            offsetof (struct malloc_chunk, fd))

为何 MIN_LARGE_SIZE 是1024?512是32位,1024是64位。

这里重点解释一下smallbin_index

sz >> 4 其实就是等于 sz / 16,而接下来是用smallbin_index算出的idx去索引bin,sz是长度,是申请的内存块的长度,那这里其实的意思就是,bin是一个结构体数组,数组里面每个元素代表着一种长度,长度的间隔是16。

那bin具体怎样的呢,往下看。

#define NBINS 128

struct malloc_state
{
    ....
    mchunkptr top;
    mchunkptr last_remainder;
    mchunkptr bins[NBINS * 2 - 2];
    ....
}

typedef struct malloc_chunk* mchunkptr;

struct malloc_chunk {

    size_t      mchunk_prev_size;  /* Size of previous chunk (if free).  */
    size_t      mchunk_size;       /* Size in bytes, including overhead. */

    struct malloc_chunk* fd;         /* double links -- used only if free. */
    struct malloc_chunk* bk;

    /* Only used for large blocks: pointer to next larger size.  */
    struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */
    struct malloc_chunk* bk_nextsize;
};

bin_at展示的是一种典型的c中指针应用法,但是就不展开说了,车控制不住。

回头看看malloc_chunk里面的fd和bk,再看看注释,是不是很明显了,双链,每个释放掉的内存块就会根据大小链在对应的bin中,而且,每个内存块都保证是16的倍数。

[1]

#define last(b) (b)->bk

这一句的意思就是说,看看这个是不是空的,没有内存块的,初始化时,其实就是bk,fd都指向自己。

[2]

malloc_consolidate调用的是malloc_init_state

static void
malloc_init_state (mstate av)
{
    int     i;
    mbinptr bin;

    /* Establish circular links for normal bins */
    for (i = 1; i < NBINS; ++i) {
        bin = bin_at (av, i);
        bin->fd = bin->bk = bin;
    }

#if MORECORE_CONTIGUOUS
    if (av != &main_arena)
#endif
        set_noncontiguous (av);

    if (av == &main_arena)
        set_max_fast (DEFAULT_MXFAST);

    av->flags |= FASTCHUNKS_BIT;
    av->top = initial_top (av);
}

bin->fd = bin->bk = bin; 这一句就解释了 if ((victim = last (bin)) != bin) 这一句的来源了。其他代码就是设置标记。

[3]

把内存块拿下来,补链表,返回内存块。

结尾


虽然,没有看到bin里面的内存块是怎么放上去的,不过,起码知道,是根据内存大小分区存储,每个区是16字节差距,另外也知道是用双链表。这里已经符合了开头注释,最佳适配,用idx适配,池缓存,双链表缓存。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值