LiteOS内核源码分析系列十四 动态内存Bestfit_little分配算法

举报
zhushy 发表于 2021/04/21 09:51:56 2021/04/21
【摘要】 LiteOS内核源码分析系列十四 动态内存Bestfit_little分配算法内存管理模块管理系统的内存资源,它是操作系统的核心模块之一,主要包括内存的初始化、分配以及释放。在系统运行过程中,内存管理模块通过对内存的申请/释放来管理用户和OS对内存的使用,使内存的利用率和使用效率达到最优,同时最大限度地解决系统的内存碎片问题。Huawei LiteOS的内存管理分为静态内存管理和动态内存管...

LiteOS内核源码分析系列十四 动态内存Bestfit_little分配算法

内存管理模块管理系统的内存资源,它是操作系统的核心模块之一,主要包括内存的初始化、分配以及释放。

在系统运行过程中,内存管理模块通过对内存的申请/释放来管理用户和OS对内存的使用,使内存的利用率和使用效率达到最优,同时最大限度地解决系统的内存碎片问题。

Huawei LiteOS的内存管理分为静态内存管理和动态内存管理,提供内存初始化、分配、释放等功能。

  • 动态内存:在动态内存池中分配用户指定大小的内存块。

    • 优点:按需分配。
    • 缺点:内存池中可能出现碎片。
  • 静态内存:在静态内存池中分配用户初始化时预设(固定)大小的内存块。

    • 优点:分配和释放效率高,静态内存池中无碎片。
    • 缺点:只能申请到初始化预设大小的内存块,不能按需申请。

上一系列分析了静态内存,我们开始分析动态内存。动态内存管理主要用于用户需要使用大小不等的内存块的场景。当用户需要使用内存时,可以通过操作系统的动态内存申请函数索取指定大小的内存块,一旦使用完毕,通过动态内存释放函数归还所占用内存,使之可以重复使用。

LiteOS动态内存支持bestfit(也称为dlink)和bestfit_little两种内存管理算法。上一系系列已经分析过动态内存的bestfit的算法,本文继续分析LiteOS动态内存的bestfit_little算法。

本文通过分析LiteOS动态内存模块的源码,帮助读者掌握动态内存的使用。LiteOS动态内存模块的源代码,均可以在LiteOS开源站点https://gitee.com/LiteOS/LiteOS 获取。动态内存bestfit_little算法的源代码、开发文档,示例程序代码如下:


接下来,我们看下动态内存的结构体,动态内存初始化,动态内存常用操作的源代码。

1、动态内存结构体定义和常用宏定义

1.1 动态内存结构体定义

动态内存bestfit_little算法的结构体有动态内存池信息结构体LosMemPoolInfo即内存管理节点struct LosHeapManager,动态内存节点结构体LosHeapNode。本系列先不考虑对SLAB内存的支持。

1.1.1 动态内存池信息结构体LosMemPoolInfo

在文件kernel\base\include\los_memory_pri.h中,定义了内存池信息结构体LosMemPoolInfo。动态内存bestfit算法和bestfit_little算法中都定义了该结构体,结构体名称一样,成员有差异,我们本系列看看bestfit_little算法的结构体,源代码如下。三个主要的成员是内存池头节点struct LosHeapNode *head、内存池尾节点struct LosHeapNode *tail和内存池大小UINT32 size。其他结构体需要开启相应的宏才生效,暂不讨论这些宏相关的特性。

typedef struct LosHeapManager {
    struct LosHeapNode *head;
    struct LosHeapNode *tail;
    UINT32 size;

#ifdef LOSCFG_MEM_TASK_STAT
    Memstat stat;
#endif

#ifdef LOSCFG_MEM_MUL_POOL
    VOID *nextPool;
#endif

#ifdef LOSCFG_KERNEL_MEM_SLAB_EXTENTION
    struct LosSlabControlHeader slabCtrlHdr;
#endif
} LosMemPoolInfo;

1.1.2 动态内存池节点结构体LosHeapNode

在文件kernel\base\mem\bestfit_little\los_memory_internal.h中,定义了动态内存池节点结构体LosHeapNode。结构体源代码如下,非常简单,成员包含指向上一个节点的指针struct LosHeapNode *prev,节点的大小size,是否使用标记used,是否对齐标记align,数据区地址UINT8 data[0]

struct LosHeapNode {
    struct LosHeapNode *prev;
#ifdef LOSCFG_MEM_TASK_STAT
    UINT32 taskId;
#endif
    UINT32 size     : 30;
    UINT32 used     : 1;
    UINT32 align    : 1;
    UINT8  data[0];
};

1.2 动态内存常用宏定义

我们先看看使用到的宏定义,这些宏非常重要,在分析源代码前需要熟悉下这些宏的定义。在文件kernel\base\mem\bestfit_little\los_heap.c中定义了些和heap操作相关的宏。HEAP_CAST(t, exp)用于指针类型转换,HEAP_ALIGN表示内存对齐大小,MALLOC_MAXSIZE表示允许申请的最大内存。

#define HEAP_CAST(t, exp)   ((t)(exp))

#define HEAP_ALIGN          4

#define MALLOC_MAXSIZE      (0xFFFFFFFF - HEAP_ALIGN + 1)

动态内存头文件kernel\base\mem\bestfit\los_memory_internal.h中也提供了一些重要的宏定义。

⑴处定义两个宏用于内存对齐,⑵处定义是否对齐标记位,即高31位。然后分别定义3个宏函数,OS_MEM_SET_ALIGN_FLAG()设置标记为对齐,OS_MEM_GET_ALIGN_FLAG()获取是否已对齐,OS_MEM_GET_ALIGN_GAPSIZE()获取去除标记后的使用大小。

⑴  #define ALIGNE(sz)                            (((sz) + HEAP_ALIGN - 1) & (~(HEAP_ALIGN - 1)))
    #define OS_MEM_ALIGN(value, align)            (((UINT32)(UINTPTR)(value) + (UINT32)((align) - 1)) & \
                                                (~(UINT32)((align) - 1)))
⑵  #define OS_MEM_ALIGN_FLAG                     0x80000000
    #define OS_MEM_SET_ALIGN_FLAG(align)          ((align) = ((align) | OS_MEM_ALIGN_FLAG))
    #define OS_MEM_GET_ALIGN_FLAG(align)          ((align) & OS_MEM_ALIGN_FLAG)
    #define OS_MEM_GET_ALIGN_GAPSIZE(align)       ((align) & (~OS_MEM_ALIGN_FLAG))

2、动态内存常用操作

Huawei LiteOS系统中的动态内存管理模块为用户提供初始化和删除内存池、申请、释放动态内存等操作,我们来分析下接口的源代码。在分析下内存操作接口之前,我们先看下一下常用的内部heap接口。

2.1 动态内存内部Heap接口

在文件kernel\base\mem\bestfit_little\los_heap.c中定义了内存操作相关的接口,如初始化内存池、申请、释放动态内存等。

2.1.1 堆内存初始化OsHeapInit

函数BOOL OsHeapInit(VOID *pool, UINT32 size)用于初始化堆内存,需要2个参数:VOID *pool是内存池的起始地址,UINT32 size为内存池的大小。⑴处转换内存池起始地址为内存管理节点,⑵进行参数校验,如果内存池地址为空,内存池大小小于内存管理节点和一个内存节点的大小之和,则返回初始化失败。⑶清除内存池的内容,⑷设置内存管理节点的size成员变量数据为内存节点区的大小。⑸处获取第一个内存节点的地址,该节点为内存管理节点的头结点,也是尾节点。⑹设置内存节点相关信息,大小、前一个节点指针,内存节点的数据区大小。⑺处内存使用统计暂不分析,自行查看即可。

BOOL OsHeapInit(VOID *pool, UINT32 size)
{
    struct LosHeapNode *node = NULL;struct LosHeapManager *heapMan = HEAP_CAST(struct LosHeapManager *, pool);if ((heapMan == NULL) || (size <= (sizeof(struct LosHeapNode) + sizeof(struct LosHeapManager)))) {
        return FALSE;
    }(VOID)memset_s(pool, size, 0, size);

⑷  heapMan->size = size - sizeof(struct LosHeapManager);

⑸  node = heapMan->head = (struct LosHeapNode *)((UINT8*)pool + sizeof(struct LosHeapManager));

    heapMan->tail = node;

⑹  node->used = 0;
    node->prev = NULL;
    node->size = heapMan->size - sizeof(struct LosHeapNode);OsHeapStatInit(heapMan, size);

    return TRUE;
}

2.1.2 申请内存OsHeapAlloc

函数VOID *OsHeapAlloc(VOID *pool, UINT32 size)用于申请内存块,VOID *pool为内存池起始地址,UINT32 size为要申请的内存大小。⑴处计算内存对齐后的大小,⑵转换为内存管理节点,然后进行参数校验,确保内存池地址不为空,申请的内存大小不超标。⑶处获取内存尾节点,当不为空时,循环遍历各个内存节点,寻找出最佳的满足申请大小的内存节点best。⑷处的条件表示,当内存节点未使用,节点大小满足申请的内存大小,并且内存节点的大小小于已遍历的最佳节点时,把当前节点设置为最佳的节点。⑸如果节点大小刚刚好,跳转到SIZE_MATCH标签。

⑹如果最佳节点为空,表示申请失败,返回。⑺处处理最佳节点的大小超出申请的大小的情况,⑻处表示去掉申请的内存块后剩余的内存节点node,然后标记该剩余节点的信息,包含未使用标记,大小,上一个节点等信息。⑼如果最佳内存节点不是尾节点,执行⑽后续下一个节点,把下一个内存节点的上一个节点设置为剩余内存节点node。⑾表示如果最佳节点是尾节点,则把剩余节点设置为尾节点。⑿处的SIZE_MATCH把申请的内存节点设置为已使用,然后把返回指针设置为节点的数据区起始地址best->data

VOID *OsHeapAlloc(VOID *pool, UINT32 size)
{
    struct LosHeapNode *node = NULL;
    struct LosHeapNode *next = NULL;
    struct LosHeapNode *best = NULL;
    VOID *ptr = NULL;
⑴  UINT32 alignSize = ALIGNE(size);struct LosHeapManager *heapMan = HEAP_CAST(struct LosHeapManager *, pool);
    if ((heapMan == NULL) || (size > MALLOC_MAXSIZE)) {
        return NULL;
    }

    if (OsHeapIntegrityCheck(heapMan) != LOS_OK) {
        return NULL;
    }

⑶  node = heapMan->tail;
    while (node != NULL) {if ((node->used == 0) && (node->size >= alignSize) &&
            ((best == NULL) || (best->size > node->size))) {
            best = node;if (best->size == alignSize) {
                goto SIZE_MATCH;
            }
        }
        node = node->prev;
    }if (best == NULL) {
        PRINT_ERR("there's not enough whole to alloc 0x%x Bytes!\n", alignSize);
        goto OUT;
    }if ((best->size - alignSize) > sizeof(struct LosHeapNode)) {
⑻      node = (struct LosHeapNode*)(UINTPTR)(best->data + alignSize);
        node->used = 0;
        node->size = best->size - alignSize - sizeof(struct LosHeapNode);
        node->prev = best;if (best != heapMan->tail) {
⑽          next = OsHeapPrvGetNext(heapMan, node);
            if (next != NULL) {
                next->prev = node;
            }
        } else {
⑾          heapMan->tail = node;
        }

        best->size = alignSize;
    }

SIZE_MATCH:
⑿  best->align = 0;
    best->used = 1;
    ptr = best->data;

    OsHeapStatAddUsed(heapMan, best);
OUT:
    return ptr;
}

2.1.3 按指定字节内存对齐申请内存OsHeapAllocAlign

函数VOID* OsHeapAllocAlign(VOID *pool, UINT32 size, UINT32 boundary)用于从指定动态内存池中申请长度为size且地址按boundary字节对齐的内存。该函数需要3个参数,VOID *pool为内存池起始地址,UINT32 size为需要申请的内存大小,UINT32 boundary内存对齐数值。当使用函数OsHeapAlloc()申请内存后得到的内存地址VOID *ptr,对齐后的内存地址为VOID *alignedPtr,二者的偏移值使用UINT32 gapSize保存。下面分析下源码。

⑴处对参数进行校验,内存池地址不能为空,申请的内存大小不能为0,对齐字节boundary不能小于4,且按自身进行对齐。⑵处计算对齐后需要申请的内存大小,⑶处调用函数申请到内存VOID *ptr,然后计算出对齐的内存地址VOID *alignedPtr,如果二者相等则返回。⑷处计算出对齐内存的偏移值,对偏移值设置对齐标记,然后执行⑸把偏移值保存在内存VOID *alignedPtr的前4个字节里。重新定向要返回的指针,完成申请对齐的内存。

VOID* OsHeapAllocAlign(VOID *pool, UINT32 size, UINT32 boundary)
{
    UINT32 useSize;
    UINT32 gapSize;
    VOID *ptr = NULL;
    VOID *alignedPtr = NULL;if ((pool == NULL) || (size == 0) || (boundary < sizeof(VOID *)) || !IS_ALIGNED(boundary, boundary)) {
        return NULL;
    }

⑵  useSize = (size + boundary) - sizeof(VOID*);
    if (useSize < size) {
        return NULL;
    }

⑶  ptr = OsHeapAlloc(pool, useSize);
    if (ptr != NULL) {
        alignedPtr = (VOID *)(UINTPTR)OS_MEM_ALIGN(ptr, boundary);
        if (alignedPtr == ptr) {
            goto OUT;
        }

⑷      gapSize = (UINTPTR)alignedPtr - (UINTPTR)ptr;
        OS_MEM_SET_ALIGN_FLAG(gapSize);*((UINT32 *)((UINTPTR)alignedPtr - sizeof(UINTPTR))) = gapSize;

        ptr = alignedPtr;
    }
OUT:
    return ptr;
}

2.1.4 释放内存OsHeapFree

BOOL OsHeapFree(VOID *pool, VOID *ptr)函数用于从内存池释放内存,需要2个参数,VOID *pool是初始化过的静态内存池地址。VOID *ptr是需要释放的动态内存块的数据区的起始地址,注意这个不是内存控制节点的地址。下面分析下源码。

⑴处转换内存池起始地址获取管理节点,然后对传入的参数先进行校验。⑵处获取偏移值gapSize。⑶处如果偏移值设置了对齐标记,表示是要释放使用OsHeapAllocAlign()函数申请的内存。⑷去除对齐标记,获取实际的偏移值,然后计算出内存的实际未对齐的指针ptr。如果是使用OsHeapAlloc()申请的内存,不存在偏移值,gapSize其实就是内存管理节点结构体的成员变量size的值。

继续执行⑸进行校验,如果指针*ptr比头节点还小,或比尾节点还大,则报错返回。⑹基于数据地址获取节点地址,然后下一步对该节点进行验证,如果验证失败则返回错误。调用⑺处函数OsHeapDoFree()进行内存释放。

BOOL OsHeapFree(VOID *pool, VOID *ptr)
{
    struct LosHeapNode *node = NULL;

    UINT32 gapSize;
    BOOL ret = TRUE;struct LosHeapManager *heapMan = HEAP_CAST(struct LosHeapManager *, pool);
    if ((heapMan == NULL) || (ptr == NULL)) {
        return LOS_NOK;
    }

⑵  gapSize = *((UINT32 *)((UINTPTR)ptr - sizeof(UINTPTR)));if (OS_MEM_GET_ALIGN_FLAG(gapSize)) {
⑷      gapSize = OS_MEM_GET_ALIGN_GAPSIZE(gapSize);
        ptr = (VOID *)((UINTPTR)ptr - gapSize);
    }if (((UINTPTR)ptr < (UINTPTR)heapMan->head) ||
        ((UINTPTR)ptr > ((UINTPTR)heapMan->tail + sizeof(struct LosHeapNode)))) {
        PRINT_ERR("0x%lx out of range!\n", (UINTPTR)ptr);
        return FALSE;
    }

⑹   node = ((struct LosHeapNode *)ptr) - 1;
    if ((node->used == 0) || (!((UINTPTR)node == (UINTPTR)heapMan->head) &&
        (((UINTPTR)node->prev < (UINTPTR)heapMan->head) ||
        ((UINTPTR)node->prev > ((UINTPTR)heapMan->tail + sizeof(struct LosHeapNode))) ||
        ((UINTPTR)OsHeapPrvGetNext(heapMan, node->prev) != (UINTPTR)node)))) {
        ret = FALSE;
        goto OUT;
    }

    OsHeapStatDecUsed(heapMan, node);OsHeapDoFree(heapMan, node);

OUT:
    return ret;
}

我们看下函数OsHeapDoFree()。⑴把要释放的节点设置为未使用状态,⑵处循环遍历要释放的节点前序节点,指向第一个未使用的节点,然后执行⑶获取第一个未使用的节点的下一个节点。⑷从第一未使用的节点循环遍历后续每一个节点。⑸如果遍历到使用中的节点,把使用的节点的前序节点设置为node,然后跳出循环。⑹如果遍历的节点都是未使用的节点,则把大小合并到第一个节点。⑺如果遍历到尾节点,则更新尾节点为node。⑻更新循环条件,持续获取下一个节点。

STATIC VOID OsHeapDoFree(struct LosHeapManager *heapMan, struct LosHeapNode *curNode)
{
    struct LosHeapNode *node = curNode;
    struct LosHeapNode *next = NULL;
⑴   node->used = 0;while ((node->prev) && (!node->prev->used)) {
        node = node->prev;
    }

⑶  next = OsHeapPrvGetNext(heapMan, node);while (next != NULL) {if (next->used) {
            next->prev = node;
            break;
        }
⑹      node->size += (sizeof(struct LosHeapNode) + next->size);if (heapMan->tail == next) {
            heapMan->tail = node;
        }
⑻      next = OsHeapPrvGetNext(heapMan, node);
    }
}

2.2 动态内存对外操作接口

2.2.1 内存初始化LOS_MemInit

我们分析下初始化动态内存池函数UINT32 LOS_MemInit(VOID *pool, UINT32 size)的代码。我们先看看函数参数,VOID *pool是动态内存池的起始地址,UINT32 size是初始化的动态内存池的总大小,size需要小于等于*pool开始的内存区域的大小,否则会影响后面的内存区域,还需要大于动态内存管理节点大小sizeof(struct LosHeapManager)

我们看下代码,⑴处对传入参数进行校验。⑵处调用函数OsHeapInit()进行内存池初始化,这是初始化的内存的核心函数。⑶处开启宏LOSCFG_KERNEL_MEM_SLAB_EXTENTION支持时,才会执行。

LITE_OS_SEC_TEXT_INIT UINT32 LOS_MemInit(VOID *pool, UINT32 size)
{
    UINT32 ret = LOS_NOK;
    UINT32 intSave;if ((pool == NULL) || (size <= sizeof(struct LosHeapManager))) {
        return ret;
    }

    MEM_LOCK(intSave);

    if (OsMemMulPoolInit(pool, size) != LOS_OK) {
        goto OUT;
    }if (OsHeapInit(pool, size) == FALSE) {
        (VOID)OsMemMulPoolDeinit(pool);
        goto OUT;
    }OsSlabMemInit(pool, size);

    ret = LOS_OK;
OUT:
    MEM_UNLOCK(intSave);

    LOS_TRACE(MEM_INFO_REQ, pool);
    return ret;
}

2.2.2 申请动态内存LOS_MemAlloc

初始化动态内存池后,我们可以使用函数VOID *LOS_MemAlloc(VOID *pool, UINT32 size)来申请动态内存,下面分析下源码。

⑴处对参数进行校验,内存池地址不能为空,申请的内存大小不能为0。⑵处如果支持SLAB,则先尝试从SLAB中获取内存,否则执行⑶调用函数OsHeapAlloc(pool, size)申请内存块。

LITE_OS_SEC_TEXT VOID *LOS_MemAlloc(VOID *pool, UINT32 size)
{
    VOID *ptr = NULL;
    UINT32 intSave;if ((pool == NULL) || (size == 0)) {
        return ptr;
    }

    MEM_LOCK(intSave);

⑵  ptr = OsSlabMemAlloc(pool, size);
    if (ptr == NULL) {
⑶       ptr = OsHeapAlloc(pool, size);
    }

    MEM_UNLOCK(intSave);

    LOS_TRACE(MEM_ALLOC, pool, (UINTPTR)ptr, size);
    return ptr;
}

2.2.3 按指定字节对齐申请动态内存LOS_MemAllocAlign

我们还可以使用函数VOID *LOS_MemAllocAlign(VOID *pool, UINT32 size, UINT32 boundary),从指定动态内存池中申请长度为size且地址按boundary字节对齐的内存。该函数需要3个参数,VOID *pool为内存池起始地址,UINT32 size为需要申请的内存大小,UINT32 boundary内存对齐数值。当申请内存后得到的内存地址VOID *ptr,对齐后的内存地址为VOID *alignedPtr,二者的偏移值使用UINT32 gapSize保存。代码如下,可以看出实际申请内存使用的是函数OsHeapAllocAlign()

LITE_OS_SEC_TEXT VOID *LOS_MemAllocAlign(VOID *pool, UINT32 size, UINT32 boundary)
{
    VOID *ptr = NULL;
    UINT32 intSave;

    MEM_LOCK(intSave);
    ptr = OsHeapAllocAlign(pool, size, boundary);
    MEM_UNLOCK(intSave);

    LOS_TRACE(MEM_ALLOC_ALIGN, pool, (UINTPTR)ptr, size, boundary);
    return ptr;
}

2.2.4 释放动态内存

对申请的内存块使用完毕,我们可以使用函数UINT32 LOS_MemFree(VOID *pool, VOID *ptr)来释放静态内存,需要2个参数,VOID *pool是初始化过的静态内存池地址。VOID *ptr是需要释放的动态内存块的数据区的起始地址,注意这个不是内存控制节点的地址。下面分析下源码。

⑴处对传入的参数先进行校验。⑵如果内存是从SLAB中申请的内存,需要释放到SLAB内存区。⑶处调用函数OsHeapFree(pool, mem)完成内存的释放。

LITE_OS_SEC_TEXT UINT32 LOS_MemFree(VOID *pool, VOID *mem)
{
    BOOL ret = FALSE;
    UINT32 intSave;if ((pool == NULL) || (mem == NULL)) {
        return LOS_NOK;
    }

    MEM_LOCK(intSave);

⑵  ret = OsSlabMemFree(pool, mem);
    if (ret != TRUE) {
⑶      ret = OsHeapFree(pool, mem);
    }

    MEM_UNLOCK(intSave);

    LOS_TRACE(MEM_FREE, pool, (UINTPTR)mem);
    return (ret == TRUE ? LOS_OK : LOS_NOK);
}

2.2.5 重新申请动态内存

我们还可以使用函数VOID *LOS_MemRealloc(VOID *pool, VOID *ptr, UINT32 size),按size大小重新分配内存块,并将原内存块内容拷贝到新内存块。如果新内存块申请成功,则释放原内存块。该函数需要3个参数,VOID *pool为内存池起始地址,VOID *ptr为之前申请的内存地址,UINT32 size为重新申请的内存大小。下面分析下源码。

⑴处如果内存池地址不为空,入size为0,等价于函数LOS_MemFree()。⑵处如果传入的内存地址为空,则等价于LOS_MemAlloc()函数。⑶处获取内存对齐偏移值,并校验是否包含对齐标记,如果内存对齐函数LOS_MemAllocAlign()申请的内存,则返回错误,无法重现申请内存。⑷处获取内存节点地址,⑸计算出需要复制的内存空间的大小。⑹按指定的大小申请内存,然后执行⑺复制内存数据。⑻处如果复制数据成功则释放之前的内存,如果复制失败则释放重新申请的内存。执行⑼释放掉内存。

VOID *LOS_MemRealloc(VOID *pool, VOID *ptr, UINT32 size)
{
    VOID *retPtr = NULL;
    VOID *freePtr = NULL;
    UINT32 intSave;
    struct LosHeapNode *node = NULL;
    UINT32 cpySize;
    UINT32 gapSize;
    errno_t rc;if ((ptr != NULL) && (size == 0)) {
        if (LOS_MemFree(pool, ptr) != LOS_OK) {
            PRINT_ERR("LOS_MemFree error, pool[%p], pPtr[%p]\n", pool, ptr);
        }} else if (ptr == NULL) {
        retPtr = LOS_MemAlloc(pool, size);
    } else {
        MEM_LOCK(intSave);

        UINT32 oldSize = OsSlabMemCheck(pool, ptr);
        if (oldSize != (UINT32)(-1)) {
            cpySize = (size > oldSize) ? oldSize : size;
        } else {
⑶          gapSize = *((UINTPTR *)((UINTPTR)ptr - sizeof(UINTPTR)));
            if (OS_MEM_GET_ALIGN_FLAG(gapSize)) {
                MEM_UNLOCK(intSave);
                return NULL;
            }

⑷          node = ((struct LosHeapNode *)ptr) - 1;
⑸          cpySize = (size > (node->size)) ? (node->size) : size;
        }

        MEM_UNLOCK(intSave);

⑹      retPtr = LOS_MemAlloc(pool, size);
        if (retPtr != NULL) {
⑺          rc = memcpy_s(retPtr, size, ptr, cpySize);if (rc == EOK) {
                freePtr = ptr;
            } else {
                freePtr = retPtr;
                retPtr = NULL;
            }if (LOS_MemFree(pool, freePtr) != LOS_OK) {
                PRINT_ERR("LOS_MemFree error, pool[%p], ptr[%p]\n", pool, freePtr);
            }
        }
    }

    LOS_TRACE(MEM_REALLOC, pool, (UINTPTR)ptr, size);
    return retPtr;
}

小结

本文带领大家一起剖析了LiteOS动态内存模块bestfit_little算法的源代码,包含动态内存的结构体、动态内存池初始化、动态内存申请、释放等。感谢阅读,如有任何问题、建议,都可以留言给我们: https://gitee.com/LiteOS/LiteOS/issues 。为了更容易找到LiteOS代码仓,建议访问 https://gitee.com/LiteOS/LiteOS ,关注Watch、点赞Star、并Fork到自己账户下,谢谢。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。