用户态动态内存分配算法TLSF的原理及其实现(图文详解释)

(源码可私信)

线性地址连续的block通过prev_node连接。

struct tlsf_node_head {
    uint32_t magic;
    union {
        struct tlsf_node_head *prev; /* The prev is used for current node points to the previous node */
        struct tlsf_node_head *next; /* The next is used for last node points to the expand node */
    } ptr;
    uint32_t size_and_flag;   /* used to store the block size and status */
};

struct tlsf_used_node_head {
    struct tlsf_node_head header;
};

当前内存块找下一个地址连续的内存块:

#define tlsf_NEXT_NODE(node) \
        ((struct tlsf_node_head *)(void *)((uint8_t *)(node) + tlsf_NODE_GET_SIZE((node)->size_and_flag)))

当前内存块找上一个地址连续的内存块:

struct tlsf_node_head *prev_node = node->ptr.prev;

同属相同区间的空闲内存块通过内部指针相连:

struct tlsf_free_node_head {
    struct tlsf_node_head header;
    struct tlsf_free_node_head *prev;  /* used to points to prev free node */
    struct tlsf_free_node_head *next; /* used to points to next free node */
};

内存池最后设置哨兵块,用于内存块合并时判断结尾使用:

Two-level Segregate fit (两级分割算法):

标题
#define tlsf_SLI                     3	  /* 2^3 = 8, 每一个size等级被分成8份, 比如2^7~2^8-1,被分成8份 */
#define tlsf_LARGE_START_BUCKET      7   /* 大桶起始size大小 = 2^7 = 128 */
#define tlsf_LARGE_BUCKET_COUNT      24  /* 大桶按照幂级数分成24个区间,从2^7~2^30 */
#define tlsf_SMALL_BUCKET_COUNT      31  /* 小桶数量 */
#define tlsf_SMALL_BUCKET_MAX_SIZE   128 /* 小桶的最大size */

一些计算公式:

struct tlsf_free_node_head *free_list[tlsf_FREE_LIST_COUNT];

tlsf_FREE_LIST_COUNT = tlsf_SMALL_BUCKET_COUNT + tlsf_LARGE_BUCKET_COUNT * 2tlsf_SLI

#define tlsf_FREE_LIST_COUNT         (tlsf_SMALL_BUCKET_COUNT + (tlsf_LARGE_BUCKET_COUNT << tlsf_SLI))

uint32_t free_bitmap[tlsf_BITMAP_WORDS];

tlsf_BITMAP_WORDS = tlsf_FREE_LIST_COUNT/32 + 1

#define tlsf_BITMAP_WORDS            ((tlsf_FREE_LIST_COUNT >> 5) + 1)

根据size找到对应的free_list :

  1. size < 128 bytes:index = size/4 - 1;
  2. size >=128 bytes: index = (tlsf_SMALL_BUCKET_COUNT) + (log2(size)取整 - tlsf_LARGE_START_BUCKET) * 23 + sl

sl = (size - 2fl) / (2fl / 2tlsf_SLI) = [(size << tlsf_SLI) >> fl] - (1 << tlsf_SLI)

Ex: size = 129, fl = 129>>4 - 1 = 7, sl = (129 - 128)/(128/8) = 0, index = (31 + (7-7)*8 + 0 = 31,为第一个大桶的index。

内存池头:

/* mem pool head info */
struct tlsf_head_info {
    void *pool;  /* record pool addr only */
    uint32_t total_size;
};

/* mem pool head */
struct tlsf_head {
    struct tlsf_head_info info;
    uint32_t free_bitmap[tlsf_BITMAP_WORDS];
    struct tlsf_free_node_head *free_list[tlsf_FREE_LIST_COUNT];
    pthread_mutex_t head_lock;
};

内存池初始化:

动态内存申请:

动态内存申请分成3步:【根据申请的size获取空闲块】+ 【分离空闲块】+【返回用户地址】。

空闲块获取:

static uint32_t tlsf_not_empty_index_get(struct tlsf_head *pool_head, uint32_t index)
{
    uint32_t mask;

    mask = pool_head->free_bitmap[BITMAP_INDEX(index)];
    mask &= ~((1 << (index & tlsf_BITMAP_MASK)) - 1);
    if (mask != 0) {
        index = tlsf_ffs(mask) + (index & ~tlsf_BITMAP_MASK);
        return index;
    }
    /* if mask == 0, return the bigest index */
    return tlsf_FREE_LIST_COUNT;
}
static struct tlsf_free_node_head *tlsf_find_next_suitable_block(void *pool, uint32_t size, uint32_t *outindex)
{
    struct tlsf_head *pool_head = (struct tlsf_head *)pool;
    uint32_t fl = tlsf_fl_get(size);
    uint32_t sl;
    uint32_t index, tmp;
    uint32_t cur_index = tlsf_FREE_LIST_COUNT;
    uint32_t mask;

    if (size < tlsf_SMALL_BUCKET_MAX_SIZE) {
        index = fl;
    } else {
        sl = tlsf_sl_get(size, fl);
        cur_index = ((fl - tlsf_LARGE_START_BUCKET) << tlsf_SLI) + sl + tlsf_SMALL_BUCKET_COUNT;
        /* Good-fit to find the free_list in index+1 */
        index = cur_index + 1;
    }

    tmp = tlsf_not_empty_index_get(pool_head, index);
    /* find the free node for the giving index */
    if (tmp != tlsf_FREE_LIST_COUNT) {
        index = tmp;
        *outindex = index;
        return pool_head->free_list[index];
    }

    /* find the free node for the giving index to the next 32-bit boundary, always searching upwards  */
    for (index = tlsf_ALIGN(index+1, 32); index < tlsf_FREE_LIST_COUNT; index += 32) {
        mask = pool_head->free_bitmap[BITMAP_INDEX(index)];
        if (mask != 0) {
            index = tlsf_ffs(mask) + index;
            *outindex = index;
            return pool_head->free_list[index];
        }
    }

    if (cur_index == tlsf_FREE_LIST_COUNT) {
        return NULL;
    }

    /* only best-bit now, find the free node in current index */
    *outindex = cur_index;
    return tlsf_find_current_suitable_block(pool_head, cur_index, size);
}

空闲块分离:

static void tlsf_split_node(void *pool, struct tlsf_node_head *alloc_node, uint32_t alloc_size)
{
    struct tlsf_free_node_head *new_free_node = NULL;
    struct tlsf_node_head *next_node = NULL;

    /* get the next free node */
    new_free_node = (struct tlsf_free_node_head *)(void *)((uint8_t *)alloc_node + alloc_size);
    /* set the next free node prev node addr */
    new_free_node->header.ptr.prev = alloc_node;
    /* set next free node size */
    new_free_node->header.size_and_flag = alloc_node->size_and_flag - alloc_size;
    /* set the current alloc node size */
    alloc_node->size_and_flag = alloc_size;
    next_node = tlsf_NEXT_NODE(&new_free_node->header);
    /* next node is not last node */
    if (!tlsf_NODE_GET_LAST_FLAG(next_node->size_and_flag)) {
        /* set next node's prev mem node */
        next_node->ptr.prev = &new_free_node->header;
        /* How could next node is not a free node?, but it's ok to do that */
        if (!tlsf_NODE_GET_USED_FLAG(next_node->size_and_flag)) {
            tlsf_free_node_delete(pool, (struct tlsf_free_node_head *)next_node);
            /* merge next_node to new_free_node */
            tlsf_merge_node(next_node);
        }
    }

    tlsf_free_node_add(pool, new_free_node);
}

返回用户地址:

static void *tlsf_create_used_node(void *addr)
{
    struct tlsf_used_node_head *node = (struct tlsf_used_node_head *)addr;
    /* return to the user addr */
    return node + 1;
}

动态内存释放:

动态内存申请分成3步:【合并逻辑地址连续前空闲节点】+ 【合并逻辑地址连续后空闲节点】+【将空闲节点放入free list】。

static void tlsf_free(struct tlsf_head *pool, struct tlsf_node_head *node)
{
    if (!tlsf_check_used_node(pool, node)) {
        return;
    }

    /* clear the used flag */
    node->size_and_flag = tlsf_NODE_GET_SIZE(node->size_and_flag);

    /* merge prev node if prev is free */
    struct tlsf_node_head *prev_node = node->ptr.prev;
    if ((prev_node != NULL) && !tlsf_NODE_GET_USED_FLAG(prev_node->size_and_flag)) {
        tlsf_free_node_delete(pool, (struct tlsf_free_node_head *)prev_node);
        tlsf_merge_node(node);
        node = prev_node;
    }

    /* merge next node if next is free */
    struct tlsf_node_head *next_node = tlsf_NEXT_NODE(node);
    if ((next_node != NULL) && !tlsf_NODE_GET_USED_FLAG(next_node->size_and_flag)) {
        tlsf_free_node_delete(pool, (struct tlsf_free_node_head *)next_node);
        tlsf_merge_node(next_node);
    }

    /* add the node to free node list */
    tlsf_free_node_add(pool, (struct tlsf_free_node_head *)node);

    return;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小虾米的Daddy

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值