From 06b38cbc741fe409bc6329d53da599a9c79a8607 Mon Sep 17 00:00:00 2001 From: faj <1900949849@qq.com> Date: Fri, 29 Dec 2023 23:50:18 +0800 Subject: [PATCH] fuaojia/ --- src/kernel/base/mem/bestfit_little/los_heap.c | 170 ++++++++++++++++-- .../base/mem/bestfit_little/los_memory.c | 152 +++++++++++++++- .../mem/bestfit_little/los_memory_internal.h | 25 ++- .../base/mem/common/memstat/los_memstat.c | 54 ++++++ .../base/mem/common/multipool/los_multipool.c | 54 ++++++ 5 files changed, 424 insertions(+), 31 deletions(-) diff --git a/src/kernel/base/mem/bestfit_little/los_heap.c b/src/kernel/base/mem/bestfit_little/los_heap.c index 8bfa91c..3313db0 100644 --- a/src/kernel/base/mem/bestfit_little/los_heap.c +++ b/src/kernel/base/mem/bestfit_little/los_heap.c @@ -43,9 +43,9 @@ extern "C" { #endif /* __cplusplus */ #endif /* __cplusplus */ -#define HEAP_CAST(t, exp) ((t)(exp)) -#define HEAP_ALIGN sizeof(UINTPTR) -#define MALLOC_MAXSIZE (0xFFFFFFFF - HEAP_ALIGN + 1) +#define HEAP_CAST(t, exp) ((t)(exp))//这个宏定义是一个类型转换的快捷方式。它接受两个参数,t 表示目标类型,exp 是需要进行类型转换的表达式。这个宏最终会将 exp 转换为类型 t。 +#define HEAP_ALIGN sizeof(UINTPTR)//这个宏定义定义了 HEAP_ALIGN,它的值是 sizeof(UINTPTR)。sizeof 操作符用于返回其操作数的大小(以字节为单位),所以 HEAP_ALIGN 的值将取决于 UINTPTR 类型的大小。 +#define MALLOC_MAXSIZE (0xFFFFFFFF - HEAP_ALIGN + 1)//这个宏定义了 MALLOC_MAXSIZE,它的值是 0xFFFFFFFF - HEAP_ALIGN + 1。在这里,0xFFFFFFFF 表示一个32位无符号整数的最大值,HEAP_ALIGN 已经在上面定义过了。这个宏定义似乎是用来表示在分配内存时可能的最大尺寸。 /* * Description : look up the next memory node according to one memory node in the memory block list. @@ -53,13 +53,25 @@ extern "C" { * struct LosHeapNode *node --- Size of memory in bytes to allocate * Return : Pointer to next memory node */ + /*这个函数的作用是获取下一个堆节点的指针。具体实现过程如下: +如果当前节点已经是最后一个节点(即 node 等于堆管理器的尾节点),则返回 NULL。 +否则,计算出下一个节点的指针。根据结构体 LosHeapNode 的定义可知,每个节点都有一个 data 指针和一个 size 字段。为了得到下一个节点的指针,需要将当前节点的 data 指针加上当前节点的 size 字段。 +这个结果是一个地址,需要将其转换成 struct LosHeapNode* 类型的指针。可以通过先将地址转换为 UINTPTR 类型,再强制转换为 struct LosHeapNode* 来实现这一点。 +返回下一个节点的指针。*/ struct LosHeapNode* OsHeapPrvGetNext(struct LosHeapManager *heapMan, struct LosHeapNode *node) { return (heapMan->tail == node) ? NULL : (struct LosHeapNode *)(UINTPTR)(node->data + node->size); } #ifdef LOSCFG_MEM_TASK_STAT - +/*该函数接受两个参数:heapMan 表示堆管理器的指针,size 表示堆的初始大小。该函数的作用是初始化堆的统计信息, +即将 heapMan->stat 结构体清零, +并设置 heapMan->stat.memTotalUsed 和 heapMan->stat.memTotalPeak,表示内存使用情况的总量和峰值。 +具体实现过程如下: +首先调用 memset_s 函数将 heapMan->stat 清零,确保所有字段的值都为 0。 +接着,设置 heapMan->stat.memTotalUsed 的值为 sizeof(struct LosHeapNode) + sizeof(struct LosHeapManager),即堆管理器结构体和堆节点结构体的大小之和,这是堆使用的总 +将 heapMan->stat.memTotalPeak 的初始值也设为 heapMan->stat.memTotalUsed,表示在堆使用过程中的最高峰值。 +这段代码的前提条件是 LOSCFG_MEM_TASK_STAT 宏定义已经被定义,否则该函数不会被编译。*/ VOID OsHeapStatInit(struct LosHeapManager *heapMan, UINT32 size) { (VOID)memset_s(&heapMan->stat, sizeof(Memstat), 0, sizeof(Memstat)); @@ -67,7 +79,16 @@ VOID OsHeapStatInit(struct LosHeapManager *heapMan, UINT32 size) heapMan->stat.memTotalUsed = sizeof(struct LosHeapNode) + sizeof(struct LosHeapManager); heapMan->stat.memTotalPeak = heapMan->stat.memTotalUsed; } - +/*该函数的作用是向堆的统计信息中添加被使用的内存块。具体实现过程如下: +首先定义了两个变量 taskId 和 blockSize。taskId 用于记录当前任务的 ID,blockSize 表示要添加的内存块的大小, +包括堆节点结构体和节点存储的数据大小。 +然后,通过条件判断来确定 taskId 的值。如果当前任务不为空且处于非中断状态(OS_INT_INACTIVE), +则将 taskId 设置为当前任务的 ID(通过 LOS_CurTaskIDGet 函数获取)。否则,将 taskId 设置为 TASK_NUM - 1, +表示该内存块属于最后一个任务。 +将节点的 taskId 字段设置为 taskId,以便记录该内存块所属的任务。 +最后,调用 OS_MEM_ADD_USED 宏来更新堆的统计信息。该宏会将 blockSize 和 taskId 传递给堆管理器的 stat 结构体, +以便记录已使用内存的总量和各任务的内存使用情况。 +该函数的目的是在堆的统计信息中记录每个内存块的使用情况,以便进行内存管理和监控。*/ VOID OsHeapStatAddUsed(struct LosHeapManager *heapMan, struct LosHeapNode *node) { UINT32 taskId; @@ -87,7 +108,13 @@ VOID OsHeapStatAddUsed(struct LosHeapManager *heapMan, struct LosHeapNode *node) node->taskId = taskId; OS_MEM_ADD_USED(&heapMan->stat, blockSize, taskId); } - +/*该函数的作用是从堆的统计信息中减少被使用的内存块。具体实现过程如下: +首先定义了两个变量 taskId 和 blockSize。taskId 用于记录当前节点所属的任务 ID,该值在添加内存块时被设置; +blockSize 表示要减少的内存块的大小,包括堆节点结构体和节点存储的数据大小。 +调用 OS_MEM_REDUCE_USED 宏来更新堆的统计信息。该宏会将 blockSize 和 taskId 传递给堆管理器的 stat 结构体, +以便记录已使用内存的总量和各任务的内存使用情况。 +该函数的目的是在堆的统计信息中记录每个内存块的使用情况,以便进行内存管理和监控。和 OsHeapStatAddUsed 函数相反, +该函数的作用是将内存块从使用中状态转变为未使用状态。*/ VOID OsHeapStatDecUsed(struct LosHeapManager *heapMan, struct LosHeapNode *node) { UINT32 taskId = node->taskId; @@ -97,17 +124,25 @@ VOID OsHeapStatDecUsed(struct LosHeapManager *heapMan, struct LosHeapNode *node) } #else /* LOSCFG_MEM_TASK_STAT */ - +//函数用于初始化堆管理器的内存统计信息。它接受两个参数:heapMan 表示堆管理器的指针,size 表示堆的总大小。在这个备选实现中,该函数没有任何具体的实现操作,直接返回。 VOID OsHeapStatInit(struct LosHeapManager *heapMan, UINT32 size) { } - +//函数用于向堆的统计信息中添加被使用的内存块。它接受两个参数:heapMan 表示堆管理器的指针,node 表示要添加到统计信息中的堆节点指针。在这个备选实现中,该函数没有任何具体的实现操作,什么也不做。 VOID OsHeapStatAddUsed(struct LosHeapManager *heapMan, struct LosHeapNode *node) { } - +//函数用于从堆的统计信息中减少被使用的内存块。它接受两个参数:heapMan 表示堆管理器的指针,node 表示要从统计信息中减少使用的堆节点指针。在这个备选实现中,该函数没有任何具体的实现操作,什么也不做。 VOID OsHeapStatDecUsed(struct LosHeapManager *heapMan, struct LosHeapNode *node) { } #endif /* LOSCFG_MEM_TASK_STAT */ #ifdef LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK - +/*这段代码实现了一个堆完整性检查的函数 OsHeapIntegrityCheck,用于检查堆内存的完整性, +以确保堆管理器中的内存块没有被破坏或越界。让我逐步解释这段代码的功能: +首先,通过 (struct LosHeapNode *)(heap + 1) 的方式来获取第一个堆节点的地址,其中 heap 是指向堆管理器结构体的指针。 +然后,计算出堆的起始地址和结束地址,其中 heapStart 表示堆的起始地址,heapEnd 表示堆的结束地址。 +接下来进入循环,遍历堆中的每个节点。在循环内部,首先检查当前节点的地址是否位于堆的范围内,如果节点地址小于堆的起始地址或大于堆的结束地址, +则说明堆节点已经被破坏或越界,此时触发错误处理并返回 LOS_NOK 表示检查失败。 +如果当前节点的地址在合法范围内,则通过 OsHeapPrvGetNext 函数获取下一个节点的地址,继续进行下一轮的检查。 +当所有节点都通过合法性检查后,函数返回 LOS_OK 表示堆的完整性检查通过。 +总之,这段代码实现了对堆内存完整性的检查,避免了堆内存被破坏或越界,确保了堆管理器中的内存块的正确性。*/ UINT32 OsHeapIntegrityCheck(struct LosHeapManager *heap) { struct LosHeapNode *node = (struct LosHeapNode *)(heap + 1); @@ -127,7 +162,7 @@ UINT32 OsHeapIntegrityCheck(struct LosHeapManager *heap) } #else /* LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK */ - +//这段代码实现了一个名为 OsHeapIntegrityCheck 的函数,它接受一个指向 LosHeapManager 结构体的指针作为参数,并直接返回 LOS_OK。 UINT32 OsHeapIntegrityCheck(struct LosHeapManager *heap) { return LOS_OK; @@ -136,12 +171,16 @@ UINT32 OsHeapIntegrityCheck(struct LosHeapManager *heap) #endif /* LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK */ #ifdef LOSCFG_KERNEL_MEM_SLAB_EXTENTION - +/*接受一个指向内存池的指针 pool 和一个表示需要分配内存大小的参数 size。 +在函数内部,调用 OsHeapAlloc 函数将内存分配操作委托给堆内存管理器进行处理。 +最终将堆内存管理器返回的内存分配结果直接返回给调用者。*/ VOID *OsMemAlloc(VOID *pool, UINT32 size) { return OsHeapAlloc(pool, size); } - +/*接受一个指向内存池的指针 pool 和一个指向待释放内存块的指针 ptr。 +在函数内部,调用 OsHeapFree 函数将内存释放操作委托给堆内存管理器进行处理。 +检查堆内存管理器的释放操作是否成功,如果成功则返回 LOS_OK 表示释放成功,否则返回 LOS_NOK 表示释放失败。*/ UINT32 OsMemFree(VOID *pool, const VOID *ptr) { if (OsHeapFree(pool, ptr) == TRUE) { @@ -160,6 +199,19 @@ UINT32 OsMemFree(VOID *pool, const VOID *ptr) * UITN32 size --- size of the heap memory pool * Return : 1:success 0:error */ +/*这段代码实现了一个名为 OsHeapInit 的函数,用于初始化堆内存管理器。让我逐步解释这段代码的功能: +首先,函数接受一个指向内存池的指针 pool 和表示内存池大小的参数 size。 +接着,代码将 pool 指针强制类型转换为 struct LosHeapManager 类型的指针 heapMan,以便后续对堆管理器结构体成员的操作。 +然后,代码执行了一系列的条件检查: +检查 heapMan 是否为 NULL,或者内存池的大小是否小于等于堆管理器结构体和堆节点结构体所需的空间大小之和。 +如果满足其中任何一个条件,函数将返回 FALSE。 +如果条件检查通过,接下来的操作包括: +使用 memset_s 函数将整个内存池的内容初始化为 0。 +设置堆管理器结构体中的 size 成员为 size - sizeof(struct LosHeapManager)。 +将 head 和 tail 指针指向内存池中的起始位置,并初始化堆节点的相关属性,如 used、prev 和 size。 +调用 OsHeapStatInit 函数对堆内存管理器进行统计信息的初始化。 +最后,函数返回 TRUE 表示堆内存管理器初始化成功。 +总之,这段代码实现了对堆内存管理器的初始化操作,包括内存池的清零、设置管理器结构体的各个成员值,以及进行统计信息的初始化。这是堆内存分配器在启动阶段需要执行的关键操作,以确保后续的内存分配和释放能够正常进行。*/ BOOL OsHeapInit(VOID *pool, UINT32 size) { struct LosHeapNode *node = NULL; @@ -192,6 +244,33 @@ BOOL OsHeapInit(VOID *pool, UINT32 size) * UINT32 size --- size of the heap memory pool * Return : NULL:error, other value:the address of the memory we alloced */ +/*这段代码实现了一个名为 OsHeapAlloc 的函数,用于在堆内存管理器中分配指定大小的内存块。让我逐步解释这段代码的功能: + +首先,函数接受一个指向内存池的指针 pool 和表示要分配的内存块大小的参数 size。 + +接着,代码定义了一些局部变量,包括 node、next、best、ptr 和 alignSize,用于记录堆节点和其他临时数据。 + +heapMan 是将 pool 指针强制类型转换为 struct LosHeapManager 类型的指针,以便后续对堆管理器结构体成员的操作。 + +然后,代码执行了一系列的条件检查: + +检查 heapMan 是否为 NULL,或者要分配的内存块大小是否超过了最大允许的大小 MALLOC_MAXSIZE。如果满足其中任何一个条件,函数将返回 NULL。 +如果条件检查通过,接下来的操作包括: + +调用 OsHeapIntegrityCheck 函数对堆内存管理器进行完整性检查。如果检查失败(返回值不等于 LOS_OK),函数将返回 NULL。 +然后,代码从堆内存管理器的尾部开始遍历堆节点,寻找合适的空闲节点来分配内存块。具体过程如下: + +判断当前节点是否未被使用(node->used == 0)且大小足够容纳请求的对齐后的大小(node->size >= alignSize)。 +如果是,则更新 best 指针,选择找到的第一个合适的节点。 +如果找到的节点大小正好与请求的对齐后的大小相等(best->size == alignSize),跳转到 SIZE_MATCH 标签处。 +循环遍历完所有节点后,函数将根据找到的最佳节点进行不同的处理: + +如果找到了合适的节点(best != NULL),则继续下面的操作。 +如果找到的节点大小与对齐后的大小完全匹配(即跳转到 SIZE_MATCH 标签处),直接执行后续处理操作。 +否则,函数将在找到的节点上分割出一个大小为 alignSize 的内存块,并更新相关节点和管理器的属性值。 +最后,函数返回分配的内存块的起始地址 ptr。 + +总之,这段代码实现了在堆内存管理器中分配指定大小的内存块的功能。它会遍历堆节点,寻找满足条件的空闲节点,并根据需要进行内存分割,以满足对齐要求。如果分配失败或出现错误,函数将返回 NULL。*/ VOID *OsHeapAlloc(VOID *pool, UINT32 size) { struct LosHeapNode *node = NULL; @@ -222,11 +301,18 @@ VOID *OsHeapAlloc(VOID *pool, UINT32 size) } /* alloc failed */ + /*这是一个条件判断语句,如果找到的最佳节点为空(即没有足够大小的空闲节点),则执行花括号中的代码块。*/ if (best == NULL) { - PRINT_ERR("there's not enough mem to alloc 0x%x Bytes!\n", alignSize); - goto OUT; + PRINT_ERR("there's not enough mem to alloc 0x%x Bytes!\n", alignSize);//在没有足够空闲内存来分配请求大小的内存块时,打印错误信息,提示用户无法分配指定大小的内存。 + goto OUT;//跳转到标签 OUT 处,这通常是用于执行清理和释放资源的操作。 } - + /*这是另一个条件判断语句,用于判断是否有足够的空间将找到的节点分割为两部分,以满足请求的大小,并且保留一个足够大的空洞来放置下一个节点的元数据。*/ + /*node = (struct LosHeapNode*)(UINTPTR)(best->data + alignSize);:计算出新的节点的地址,该节点位于原节点的空闲空间之后,用于存放剩余的内存块。 +node->used = 0;:将新节点标记为未使用。 +node->size = best->size - alignSize - sizeof(struct LosHeapNode);:设置新节点的大小为原节点大小减去已分配内存大小和节点元数据大小的剩余空间。 +node->prev = best;:设置新节点的前驱节点为原节点。 +接下来的条件判断和操作用于更新堆管理器中的节点关系,确保堆的连续性。 +最后,best->size = alignSize;:更新原节点的大小为已分配大小,表示原节点存放了分配的内存块。*/ if ((best->size - alignSize) > sizeof(struct LosHeapNode)) { /* hole divide into 2 */ node = (struct LosHeapNode*)(UINTPTR)(best->data + alignSize); @@ -246,7 +332,11 @@ VOID *OsHeapAlloc(VOID *pool, UINT32 size) best->size = alignSize; } +/*这段代码可能是用于实现动态内存分配器的代码。具体来说,函数名称 SIZE_MATCH 可能代表了一种内存分配策略,即在进行内存分配时,选择最能够匹配请求大小的空闲内存块进行分配。 + +其中,代码中的 best 变量可能表示了符合请求大小的、最佳匹配的空闲内存块。代码将 best 的 align 属性设为 0,used 属性设为 1,表示该内存块已被使用。然后,代码通过指针 ptr 返回了该内存块的起始地址。最后,代码调用了 OsHeapStatAddUsed 函数,可能是用于统计内存分配情况的函数,将该内存块的使用信息记录到内存分配器的统计数据中。 +值得注意的是,代码中可能存在一些未给出的上下文信息,因此具体含义可能需要根据上下文和相关代码进行推断和理解。*/ SIZE_MATCH: best->align = 0; best->used = 1; @@ -264,6 +354,15 @@ OUT: * UINT32 boundary --- boundary the heap needs align * Return : NULL:error, other value:the address of the memory we alloced */ +/*这段代码是一个用于分配指定大小、指定对齐边界(alignment boundary)的内存块的函数。该函数的名称为 OsHeapAllocAlign。 + +代码首先进行了一些错误检查,确保传入的参数 pool 不为空、size 大于 0、boundary 大于等于 sizeof(VOID*)(VOID* 的大小,即指针大小),且 boundary 是对齐的。如果有任何一个条件不满足,则返回 NULL,表示内存分配失败。 + +接着,代码计算了需要分配的内存块的大小 useSize,并使用 OsHeapAlloc 函数在内存池 pool 中分配了 useSize 大小的内存块,并将其赋值给指针变量 ptr。 + +如果内存分配成功,则代码通过 OS_MEM_ALIGN 宏将 ptr 指针对齐到指定的边界 boundary。如果对齐后的指针地址与原始指针地址相同,则说明原始指针已经对齐,直接跳转到 OUT 标签处并返回 ptr 指针即可。否则,说明原始指针未对齐,需要在原始指针和对齐后的指针间填补一定的空隙(gap),并将 gap 的大小信息存储在对齐后的指针前 sizeof(UINTPTR) 个字节的位置。最后,代码返回对齐后的指针 alignedPtr。 + +需要注意的是,代码中可能存在一些未给出的宏定义和类型定义,具体含义可能需要根据上下文和相关代码进行推断和理解。*/ VOID* OsHeapAllocAlign(VOID *pool, UINT32 size, UINT32 boundary) { UINT32 useSize; @@ -297,7 +396,15 @@ VOID* OsHeapAllocAlign(VOID *pool, UINT32 size, UINT32 boundary) OUT: return ptr; } +/*这段代码是一个用于释放内存的函数,名称为 OsHeapDoFree。该函数接收两个参数:一个是 LosHeapManager 结构体指针 heapMan,代表内存池管理器;另一个是 LosHeapNode 结构体指针 curNode,代表需要释放的内存块对应的内存池节点。 + +代码首先将 curNode 赋值给 node 变量,并将其 used 属性设为 0,表示该节点为未使用状态。 + +接着,代码使用 while 循环向前遍历链表,查找前面的空闲节点。具体来说,如果当前节点 node 的前一个节点存在且未被使用,则将 node 更新为前一个节点。这一步的目的是将 node 扩展到尽可能大的空闲区域。 +然后,代码使用 while 循环向后遍历链表,查找后面的空闲节点。具体来说,代码使用 OsHeapPrvGetNext 函数获取 node 的下一个节点 next,如果 next 存在且未被使用,则将 node 和 next 合并为一个新的节点,并更新 node 的 size 属性。如果合并后的节点是链表中的最后一个节点(也就是 heapMan->tail 指向该节点),则更新 heapMan->tail 为合并后的新节点。如果 next 不存在或已经被使用,则结束循环。 + +需要注意的是,代码中使用了 LosHeapManager 和 LosHeapNode 两个结构体,具体属性和方法的含义可能需要根据上下文和相关代码进行推断和理解。*/ STATIC VOID OsHeapDoFree(struct LosHeapManager *heapMan, struct LosHeapNode *curNode) { struct LosHeapNode *node = curNode; @@ -330,6 +437,15 @@ STATIC VOID OsHeapDoFree(struct LosHeapManager *heapMan, struct LosHeapNode *cur * VOID* ptr --- the pointer of heap memory we want to free * Return : 1:success 0:error */ +/*这段代码是用于释放指定内存块的函数 OsHeapFree。该函数接收两个参数:一个是 VOID 类型指针 pool,代表内存池;另一个是 const VOID 类型指针 ptr,代表需要释放的内存块的起始地址。 + +代码首先声明了一些变量和结构体指针,其中 node 是一个 LosHeapNode 结构体指针,用于表示需要释放的内存块对应的内存池节点。gapSize 是一个 UINT32 类型变量,用于记录内存块前面的空隙大小,ret 是一个 BOOL 类型变量,用于表示内存是否成功释放。 + +接着,代码通过将传入的 ptr 指针往前移动 sizeof(UINTPTR) 个字节,找到真正的内存块地址,并将其赋值给 ptr 变量。然后,代码判断 ptr 所指向的内存块地址是否在内存池的范围内,如果不在范围内,则返回 FALSE。 + +接下来,代码使用 ((struct LosHeapNode *)ptr) - 1 计算出内存块对应的内存池节点的地址,并将其赋值给 node 变量。然后,代码检查该节点是否已经被使用,以及它是否是链表中的一个节点。如果检查不通过,则将 ret 设置为 FALSE,并跳转到 OUT 标签处。 + +最后,代码调用 OsHeapStatDecUsed 函数将内存池管理器中 used 字段减一,然后调用 OsHeapDoFree 函数将 node 对应的内存块释放,并更新内存池管理器中的相关参数。最终返回 ret 表示操作是否成功。*/ BOOL OsHeapFree(VOID *pool, const VOID *ptr) { struct LosHeapNode *node = NULL; @@ -378,6 +494,19 @@ OUT: * Output : status --- heap statistics * Return : LOS_OK on success or error code on failure */ +/*这段代码是用于获取指定内存池的统计信息的函数 OsHeapStatisticsGet。该函数接收两个参数:一个是 VOID 类型指针 pool,代表内存池;另一个是 LosHeapStatus 结构体指针 status,用于保存内存池的统计信息。 + +函数中首先声明了一些变量,包括 heapUsed、maxFreeNodeSize、freeNodeNum、usedNodeNum 以及结构体指针 node 和 ramHeap。其中 heapUsed 表示已用内存大小,maxFreeNodeSize 表示最大可用内存块大小,freeNodeNum 表示空闲节点数量,usedNodeNum 表示已用节点数量。 + +然后,代码检查传入的内存池指针是否为空,如果为空,则返回 LOS_NOK。接着,代码检查传入的结构体指针 status 是否为空,如果为空,则返回 LOS_NOK。 + +之后,代码使用 sizeof(struct LosHeapManager) 计算出内存池管理器头部占用的空间大小,并将其加到 heapUsed 变量中。 + +接下来,代码使用指针 node 遍历整个内存池的节点链表,对每个节点进行处理。如果该节点已被使用,则将其大小和节点头部大小相加,并将结果累加到 heapUsed 中,并将 usedNodeNum 加一。否则,如果该节点未被使用,则更新 maxFreeNodeSize 和 freeNodeNum 的值。 + +最后,代码检查 heapUsed 是否超过了内存池总大小,如果超过,则返回 LOS_NOK。否则,将统计信息保存到结构体指针 status 中,并返回 LOS_OK。 + +需要注意的是,如果系统开启了 LOSCFG_MEM_TASK_STAT 宏定义,则代码还会更新 usageWaterLine 字段的值。*/ UINT32 OsHeapStatisticsGet(VOID *pool, LosHeapStatus *status) { UINT32 heapUsed = 0; @@ -435,6 +564,15 @@ UINT32 OsHeapStatisticsGet(VOID *pool, LosHeapStatus *status) * Input : pool --- Pointer to the manager, to distinguish heap * Return : max free block size */ +/*这段代码是用于获取指定内存池中最大可用块大小的函数 OsHeapGetMaxFreeBlkSize。该函数接收一个参数:一个 VOID 类型指针 pool,代表内存池。 + +函数中首先声明了一些变量,包括 size、temp、结构体指针 node 和 ramHeap。其中 size 表示最大可用块大小,temp 是一个临时变量,用于保存当前节点的大小。 + +然后,代码检查传入的内存池指针是否为空,如果为空,则返回 LOS_NOK。 + +之后,代码使用指针 node 遍历整个内存池的节点链表,对每个节点进行处理。如果该节点未被使用,则将其大小保存到 temp 变量中。如果 temp 的值比 size 大,则更新 size 的值为 temp。 + +最后,函数返回 size 变量的值,即内存池中最大可用块的大小。*/ UINT32 OsHeapGetMaxFreeBlkSize(VOID *pool) { UINT32 size = 0; diff --git a/src/kernel/base/mem/bestfit_little/los_memory.c b/src/kernel/base/mem/bestfit_little/los_memory.c index cf9269d..53d9bd0 100644 --- a/src/kernel/base/mem/bestfit_little/los_memory.c +++ b/src/kernel/base/mem/bestfit_little/los_memory.c @@ -41,18 +41,40 @@ extern "C" { #endif /* __cplusplus */ #endif /* __cplusplus */ -#define POOL_ADDR_ALIGNSIZE 64 +#define POOL_ADDR_ALIGNSIZE 64//是一个宏,表示内存池地址对齐的大小,值为64。 -LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_memSpin); +LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_memSpin);//是一个修饰符,用于指定变量所属的段(section)为.bss.init,该变量在程序运行前会被初始化为0。 +//是一个宏,用于初始化自旋锁变量g_memSpin。 -UINT8 *m_aucSysMem0 = (UINT8 *)NULL; -UINT8 *m_aucSysMem1 = (UINT8 *)NULL; -__attribute__((section(".data.init"))) UINTPTR g_sys_mem_addr_end; +UINT8 *m_aucSysMem0 = (UINT8 *)NULL;//是一个指向UINT8类型的指针变量,初始值为NULL。 +UINT8 *m_aucSysMem1 = (UINT8 *)NULL;//是一个指向UINT8类型的指针变量,初始值为NULL。 +__attribute__((section(".data.init"))) UINTPTR g_sys_mem_addr_end;//是一个UINTPTR类型的变量,位于.data.init段,用于记录系统内存地址的末尾位置。 -#ifdef LOSCFG_EXC_INTERACTION -__attribute__((section(".data.init"))) UINTPTR g_excInteractMemSize = 0; + +#ifdef LOSCFG_EXC_INTERACTION//表示如果定义了宏LOSCFG_EXC_INTERACTION,则编译以下代码块。 +__attribute__((section(".data.init"))) UINTPTR g_excInteractMemSize = 0;//是一个UINTPTR类型的变量,位于.data.init段,用于记录异常交互内存的大小,初始值为0。 #endif + +/*这段代码是一个函数LOS_MemInit()的实现,用于初始化内存池。 + +LITE_OS_SEC_TEXT_INIT 是一个修饰符,用于指定函数所属的段(section)为.text.init,表示该函数在程序运行前会被初始化。 + +函数参数: + +pool 是一个指向内存池的指针,用于存储分配的内存块。 +size 是内存池的大小。 +函数内部逻辑: + +首先,函数会对传入的参数进行检查。如果pool为空指针或size小于等于sizeof(struct LosHeapManager)(一种内部结构的大小),则函数直接返回错误码LOS_NOK。 +接下来,函数会检查pool和size是否按照OS_MEM_ALIGN_SIZE(内存对齐大小)进行对齐。如果没有对齐,则打印警告信息,并将size调整为对齐后的大小。 +然后,函数会获取并保存当前的中断状态,以防止在初始化过程中发生中断。 +接着,函数调用OsMemMulPoolInit()初始化多内存池管理器,如果初始化失败,则跳转到OUT标签处。 +如果多内存池管理器初始化成功,函数继续调用OsHeapInit()初始化堆管理器。如果堆管理器初始化失败,则先释放多内存池,然后跳转到OUT标签处。 +最后,函数调用OsSlabMemInit()初始化 Slab 内存管理器,并将返回值设置为成功的状态码LOS_OK。 +在OUT标签处,函数会解锁之前保存的中断状态,并打印内存信息请求的跟踪日志。 +最终,函数返回初始化结果,可能是LOS_NOK表示失败,或者LOS_OK表示成功。 +这段代码主要实现了内存池的初始化逻辑,包括多内存池管理器、堆管理器和 Slab 内存管理器的初始化。*/ LITE_OS_SEC_TEXT_INIT UINT32 LOS_MemInit(VOID *pool, UINT32 size) { UINT32 ret = LOS_NOK; @@ -103,6 +125,21 @@ LITE_OS_SEC_TEXT_INIT UINT32 OsMemExcInteractionInit(UINTPTR memStart) * Description : Initialize Dynamic Memory pool * Return : LOS_OK on success or error code on failure */ + +/*这段代码是一个条件编译块,当定义了宏LOSCFG_EXC_INTERACTION时才会被编译。 + +LITE_OS_SEC_TEXT_INIT 是一个修饰符,用于指定函数所属的段(section)为.text.init,表示该函数在程序运行前会被初始化。 + +函数参数: + +memStart 是一个无符号整数指针,表示内存起始地址。 +函数内部逻辑: + +首先,函数将全局变量m_aucSysMem0指向memStart,即将系统内存的起始地址设为memStart。 +然后,函数将全局变量g_excInteractMemSize设置为宏定义EXC_INTERACT_MEM_SIZE的值,表示异常交互内存区域的大小。 +接下来,函数调用LOS_MemInit()函数,将m_aucSysMem0和g_excInteractMemSize作为参数进行内存初始化操作,并将返回结果保存在变量ret中。 +最后,函数打印一条信息,包含异常交互内存的地址和大小,并将初始化结果ret作为返回值返回。 +这段代码主要是用于初始化异常交互内存,通过调用LOS_MemInit()函数来初始化系统内存,并打印初始化信息。条件编译的目的是根据是否定义了LOSCFG_EXC_INTERACTION宏来控制代码的编译和执行。*/ LITE_OS_SEC_TEXT_INIT UINT32 OsMemSystemInit(UINTPTR memStart) { UINT32 ret; @@ -121,6 +158,18 @@ LITE_OS_SEC_TEXT_INIT UINT32 OsMemSystemInit(UINTPTR memStart) * Description : print heap information * Input : pool --- Pointer to the manager, to distinguish heap */ +/*这段代码是用于打印内存池(pool)信息的函数,接收一个pool指针作为参数。 + +函数参数: + +pool 是一个指向内存池的指针,用于获取内存池的信息。 +函数内部逻辑: + +首先,函数将传入的pool指针转换为LosHeapManager结构体类型的指针,并赋值给变量heapMan。 +然后,函数定义了一个LosHeapStatus类型的变量status,用于保存堆管理器的状态信息。 +接着,函数调用OsHeapStatisticsGet()函数获取堆管理器的状态信息,并将其保存在status变量中。如果函数返回错误码LOS_NOK,则函数直接返回。 +最后,函数打印一条包含内存池信息的日志信息,包括内存池地址、内存池大小、已使用内存大小、空闲内存大小、最大空闲节点大小、已分配节点数量和空闲节点数量。 +这段代码主要是用于获取内存池的状态信息,并打印到控制台或日志文件中,方便调试和排查内存泄漏等问题。*/ VOID OsMemInfoPrint(const VOID *pool) { struct LosHeapManager *heapMan = (struct LosHeapManager *)pool; @@ -136,6 +185,20 @@ VOID OsMemInfoPrint(const VOID *pool) status.usedNodeNum, status.freeNodeNum); } +/*这段代码是用于内存分配的函数,可以从指定的内存池中分配一块指定大小的内存。 + +函数参数: + +pool 是一个指向内存池的指针,用于从该内存池中分配内存。 +size 是需要分配的内存大小。 +函数内部逻辑: + +首先,函数定义了一个空指针ptr,用于保存分配到的内存块地址。 +然后,函数检查传入的参数,如果pool为空或者size为0,则直接返回空指针。 +接着,函数锁住中断,调用OsSlabMemAlloc()函数尝试从内存池的SLAB分配器中获取一块指定大小的内存。如果分配成功,则将返回的内存地址保存在ptr中。 +如果从SLAB分配器中分配内存失败,则调用OsHeapAlloc()函数从堆内存中分配一块指定大小的内存,并将返回的内存地址保存在ptr中。 +最后,函数解锁中断,记录内存分配操作的追踪日志,并返回分配到的内存地址。 +这段代码主要是用于从内存池中分配内存,首先尝试从SLAB分配器中获取内存,如果失败则从堆内存中获取。在获取内存时还记录了内存分配操作的追踪日志,方便调试和内存优化。*/ LITE_OS_SEC_TEXT VOID *LOS_MemAlloc(VOID *pool, UINT32 size) { VOID *ptr = NULL; @@ -158,6 +221,19 @@ LITE_OS_SEC_TEXT VOID *LOS_MemAlloc(VOID *pool, UINT32 size) return ptr; } +/*这段代码是用于按指定对齐边界分配内存的函数,可以从指定的内存池中分配一块指定大小、按指定对齐边界对齐的内存。 + +函数参数: + +pool 是一个指向内存池的指针,用于从该内存池中分配内存。 +size 是需要分配的内存大小。 +boundary 是需要对齐的边界大小。返回的内存地址将会是该边界的整数倍。 +函数内部逻辑: + +首先,函数定义了一个空指针ptr,用于保存分配到的内存块地址。 +然后,函数锁住中断,调用OsHeapAllocAlign()函数从堆内存中按指定对齐边界分配一块指定大小的内存。如果分配成功,则将返回的内存地址保存在ptr中。 +最后,函数解锁中断,记录内存分配操作的追踪日志,并返回分配到的内存地址。 +这段代码主要是用于从内存池中按指定对齐边界分配内存,只能在堆内存上操作。在分配内存时还记录了内存分配操作的追踪日志,方便调试和内存优化。*/ LITE_OS_SEC_TEXT VOID *LOS_MemAllocAlign(VOID *pool, UINT32 size, UINT32 boundary) { VOID *ptr = NULL; @@ -171,6 +247,14 @@ LITE_OS_SEC_TEXT VOID *LOS_MemAllocAlign(VOID *pool, UINT32 size, UINT32 boundar return ptr; } + +/*这段代码是用于重新分配内存大小的函数,主要有以下几个步骤: + +首先判断需要重新分配大小的指针ptr是否为空,如果为空,说明需要分配一块新的内存,直接调用LOS_MemAlloc()函数从内存池中分配一块指定大小的内存并返回。 +如果需要重新分配大小的指针ptr不为空且所需大小为0,则将该指针对应的内存块释放掉。 +如果需要重新分配大小的指针ptr不为空且所需大小非0,则需要从堆内存中分配一块新的内存,并将原内存中的数据拷贝到新内存中。这里在拷贝数据之前,需要先判断原内存地址是否合法。具体方法是通过OsSlabMemCheck()函数检查该指针是否属于内存池中的某个内存块,若是,则复制原内存中的数据;否则,根据原内存指针前面存储的一个整数值(表示实际内存块的大小和对齐状态)找到真正的内存块,再进行内存拷贝。 +将原内存块释放掉,返回分配到的新内存地址。 +这段代码的作用是实现重新分配内存大小的功能,可以对已经分配的内存进行扩展或缩小。在实现过程中,需要考虑到原内存块中已经存储的数据,避免无意义的内存拷贝操作。*/ VOID *LOS_MemRealloc(VOID *pool, VOID *ptr, UINT32 size) { VOID *retPtr = NULL; @@ -228,6 +312,15 @@ VOID *LOS_MemRealloc(VOID *pool, VOID *ptr, UINT32 size) return retPtr; } +/*这段代码是用于释放内存的函数,主要有以下几个步骤: + +首先判断内存池指针pool和需要释放的内存指针mem是否为空,如果其中任意一个为空,则返回错误码LOS_NOK表示释放失败。 +获取并保存当前的中断状态,以便后续恢复。 +调用OsSlabMemFree()函数尝试从内存池中释放指定的内存块。若成功释放,则将返回值设置为TRUE,否则继续执行下一步。 +如果调用OsSlabMemFree()函数失败,说明该内存块不是由内存池分配的,需要调用OsHeapFree()函数尝试从堆内存中释放指定的内存块。同样,若成功释放,则将返回值设置为TRUE,否则返回值保持为FALSE。 +恢复之前保存的中断状态。 +根据最终的返回值,如果为TRUE,则返回成功码LOS_OK,否则返回失败码LOS_NOK。 +这段代码的作用是实现内存的释放功能。首先尝试从内存池中释放内存,如果失败,则再尝试从堆内存中释放内存。通过这两种方式,可以确保能够释放从内存池或堆中分配的内存块。*/ LITE_OS_SEC_TEXT UINT32 LOS_MemFree(VOID *pool, VOID *mem) { BOOL ret = FALSE; @@ -250,6 +343,17 @@ LITE_OS_SEC_TEXT UINT32 LOS_MemFree(VOID *pool, VOID *mem) return (ret == TRUE ? LOS_OK : LOS_NOK); } +/*这段代码是用于获取内存池状态信息的函数,主要有以下几个步骤: + +首先判断内存池指针pool和状态信息指针status是否为空,如果其中任意一个为空,则返回错误码LOS_NOK表示获取失败。 +声明一个LosHeapStatus结构体类型的变量heapStatus,用于保存堆内存的状态信息。 +声明一个错误码变量err和一个中断状态变量intSave。 +获取并保存当前的中断状态,以便后续恢复。 +调用OsHeapStatisticsGet()函数获取指定内存池的堆内存状态信息,将结果保存在heapStatus中。如果返回错误码不等于LOS_OK,则表示获取失败,释放锁并返回错误码LOS_NOK。 +将获取到的堆内存状态信息赋值给传入的status参数,包括总使用大小、总空闲大小、最大空闲节点大小、已使用节点数量和空闲节点数量。 +如果配置了任务内存统计,则还会将使用的峰值赋值给status的uwUsageWaterLine字段。 +释放锁并返回成功码LOS_OK。 +这段代码的作用是获取指定内存池的状态信息,包括已使用的内存大小、空闲的内存大小、最大空闲节点的大小等。通过这些状态信息,可以了解内存池的使用情况,并进行相应的优化和管理。*/ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemInfoGet(VOID *pool, LOS_MEM_POOL_STATUS *status) { LosHeapStatus heapStatus; @@ -282,6 +386,15 @@ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemInfoGet(VOID *pool, LOS_MEM_POOL_STATUS *st return LOS_OK; } +/*这段代码是用于获取指定内存池已使用内存大小的函数,主要有以下几个步骤: + +首先判断内存池指针pool是否为空,如果为空,则返回错误码OS_NULL_INT表示获取失败。 +声明一个LosHeapStatus结构体类型的变量heapStatus,用于保存堆内存的状态信息。 +声明一个错误码变量err和一个中断状态变量intSave。 +获取并保存当前的中断状态,以便后续恢复。 +调用OsHeapStatisticsGet()函数获取指定内存池的堆内存状态信息,将结果保存在heapStatus中。如果返回错误码不等于LOS_OK,则表示获取失败,释放锁并返回错误码OS_NULL_INT。 +释放锁并返回堆内存的总使用大小。 +这段代码的作用是获取指定内存池已使用的内存大小。通过该函数可以了解内存池的已使用情况,以便进行相应的管理和优化。*/ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemTotalUsedGet(VOID *pool) { LosHeapStatus heapStatus; @@ -303,6 +416,13 @@ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemTotalUsedGet(VOID *pool) return heapStatus.totalUsedSize; } +/*这段代码是用于获取指定内存池的大小的函数,主要有以下几个步骤: + +首先判断内存池指针pool是否为空,如果为空,则返回错误码OS_NULL_INT表示获取失败。 +声明一个LosHeapManager结构体类型的指针变量heapManager,用于保存内存池的管理信息。 +将传入的内存池指针转换为LosHeapManager类型的指针,并将结果保存在heapManager中。 +返回内存池的大小,即heapManager->size。 +这段代码的作用是获取指定内存池的大小。通过该函数可以了解内存池的大小,以便进行相应的管理和优化。*/ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemPoolSizeGet(const VOID *pool) { struct LosHeapManager *heapManager = NULL; @@ -315,6 +435,14 @@ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemPoolSizeGet(const VOID *pool) return heapManager->size; } +/*这段代码是用于对指定内存池进行完整性检查的函数,主要有以下几个步骤: + +首先判断内存池指针pool是否为空,如果为空,则返回错误码OS_NULL_INT表示检查失败。 +声明一个中断状态变量intSave和一个无符号整型变量ret用于保存检查结果。 +获取并保存当前的中断状态,以便后续恢复。 +调用OsHeapIntegrityCheck()函数对指定的内存池进行完整性检查,并将检查结果保存在ret中。如果返回的结果不为0,则表示检查失败。 +释放锁并返回检查结果。 +这段代码的作用是对指定的内存池进行完整性检查,以确保内存池中的数据没有被破坏或溢出。通过该函数可以及时发现内存池中的问题,并采取相应的措施进行修复或处理。*/ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemIntegrityCheck(VOID *pool) { UINT32 intSave; @@ -331,6 +459,16 @@ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MemIntegrityCheck(VOID *pool) return ret; } +/*这段代码是用于对多个内存池进行完整性检查的函数,主要有以下几个步骤: + +首先调用LOS_MemIntegrityCheck()函数对系统内存池m_aucSysMem1进行完整性检查,并判断返回值是否为LOS_OK。 +如果检查通过,则在控制台输出一条信息表示检查成功,并在需要时将该信息写入异常信息缓冲区。 +如果系统内存池检查未通过,则不进行任何处理。 +如果宏定义LOSCFG_EXC_INTERACTION被定义,则继续执行下面的代码,否则直接结束函数。 +调用LOS_MemIntegrityCheck()函数对异常交互内存池m_aucSysMem0进行完整性检查,并判断返回值是否为LOS_OK。 +如果检查通过,则在控制台输出一条信息表示检查成功,并在需要时将该信息写入异常信息缓冲区。 +如果异常交互内存池检查未通过,则不进行任何处理。 +这段代码的作用是对多个内存池进行完整性检查,以确保内存池中的数据没有被破坏或溢出。通过该函数可以及时发现内存池中的问题,并采取相应的措施进行修复或处理。*/ VOID OsMemIntegrityMultiCheck(VOID) { if (LOS_MemIntegrityCheck(m_aucSysMem1) == LOS_OK) { diff --git a/src/kernel/base/mem/bestfit_little/los_memory_internal.h b/src/kernel/base/mem/bestfit_little/los_memory_internal.h index 2aeb022..52e29ff 100644 --- a/src/kernel/base/mem/bestfit_little/los_memory_internal.h +++ b/src/kernel/base/mem/bestfit_little/los_memory_internal.h @@ -42,13 +42,18 @@ extern "C" { #endif /* __cplusplus */ #endif /* __cplusplus */ - +//用于将指定的大小 sz 进行对齐,返回对齐后的大小。它使用 HEAP_ALIGN 宏定义来指定对齐的字节数,通过将 sz 加上 HEAP_ALIGN - 1,然后按位取反与运算(&)来实现向上对齐。 #define ALIGNE(sz) (((sz) + HEAP_ALIGN - 1) & (~(HEAP_ALIGN - 1))) +//用于将指定的 value 进行 align 字节对齐,返回对齐后的值。它将 value 转换为 UINT32 类型,并将其与 align - 1 按位取反与运算,即将 value 向上舍入到最近的 align 的倍数。 #define OS_MEM_ALIGN(value, align) (((UINT32)(UINTPTR)(value) + (UINT32)((align) - 1)) & \ (~(UINT32)((align) - 1))) +//用于表示对齐标志的宏定义,其值为 0x80000000。 #define OS_MEM_ALIGN_FLAG 0x80000000 +//用于设置对齐标志的宏定义,将传入的 align 参数按位或运算与 OS_MEM_ALIGN_FLAG 进行组合。 #define OS_MEM_SET_ALIGN_FLAG(align) ((align) = ((align) | OS_MEM_ALIGN_FLAG)) +//用于获取对齐标志的宏定义,将传入的 align 参数与 OS_MEM_ALIGN_FLAG 进行按位与运算,得到对齐标志。 #define OS_MEM_GET_ALIGN_FLAG(align) ((align) & OS_MEM_ALIGN_FLAG) +//用于获取对齐间隙大小的宏定义,将传入的 align 参数与 ~OS_MEM_ALIGN_FLAG 进行按位与运算,得到去除对齐标志后的值。 #define OS_MEM_GET_ALIGN_GAPSIZE(align) ((align) & (~OS_MEM_ALIGN_FLAG)) typedef struct tagLosHeapStatus { @@ -60,8 +65,12 @@ typedef struct tagLosHeapStatus { #ifdef LOSCFG_MEM_TASK_STAT UINT32 usageWaterLine; #endif -} LosHeapStatus; +} LosHeapStatus;//结构体:描述了内存堆的状态信息,包括总共使用的大小、总共空闲的大小、最大空闲节点的大小、已用节点数和空闲节点数等字段。 +/*结构体:描述了内存堆中的每个节点,包括前一个节点指针、任务 ID、节点大小、 +是否已经被使用、是否需要对齐等字段。这里使用了位域来节省空间, +并且使用了一个长度为 0 的数组 data[0] 来占位, +方便动态分配内存。*/ struct LosHeapNode { struct LosHeapNode *prev; #ifdef LOSCFG_MEM_TASK_STAT @@ -73,12 +82,12 @@ struct LosHeapNode { UINT8 data[0]; }; -extern BOOL OsHeapInit(VOID *pool, UINT32 size); -extern VOID* OsHeapAlloc(VOID *pool, UINT32 size); -extern VOID* OsHeapAllocAlign(VOID *pool, UINT32 size, UINT32 boundary); -extern BOOL OsHeapFree(VOID *pool, const VOID* ptr); -extern UINT32 OsHeapStatisticsGet(VOID *pool, LosHeapStatus *status); -extern UINT32 OsHeapIntegrityCheck(struct LosHeapManager *heap); +extern BOOL OsHeapInit(VOID *pool, UINT32 size);//函数声明:用于初始化内存池,即将一块内存空间转化为一个内存堆,并返回是否初始化成功。 +extern VOID* OsHeapAlloc(VOID *pool, UINT32 size);//函数声明:用于在内存堆上分配一块指定大小的内存,并返回分配到的内存地址。 +extern VOID* OsHeapAllocAlign(VOID *pool, UINT32 size, UINT32 boundary);//函数声明:用于在内存堆上分配一块指定大小并且按照给定对齐边界对齐的内存,并返回分配到的内存地址。 +extern BOOL OsHeapFree(VOID *pool, const VOID* ptr);//函数声明:用于释放内存堆中的指定内存地址所对应的节点,返回是否释放成功。 +extern UINT32 OsHeapStatisticsGet(VOID *pool, LosHeapStatus *status);//函数声明:用于获取内存堆的状态信息,并将其保存在传入的 LosHeapStatus 结构体中,返回获取到的信息字节数。 +extern UINT32 OsHeapIntegrityCheck(struct LosHeapManager *heap);//函数声明:用于检查整个内存堆的完整性,即检查是否存在内存泄漏或内存重叠等问题。 #ifdef __cplusplus #if __cplusplus diff --git a/src/kernel/base/mem/common/memstat/los_memstat.c b/src/kernel/base/mem/common/memstat/los_memstat.c index 7517b88..b0dc92c 100644 --- a/src/kernel/base/mem/common/memstat/los_memstat.c +++ b/src/kernel/base/mem/common/memstat/los_memstat.c @@ -39,6 +39,15 @@ extern "C" { #define MIN_TASK_ID(x, y) ((x) > (y) ? (y) : (x)) #define MAX_MEM_USE(x, y) ((x) > (y) ? (x) : (y)) +/*这段代码是一个函数OsMemstatTaskUsedInc的实现,用于更新内存统计信息。 + +代码首先获取任务ID的最小值,确保不越界。然后通过stat参数获取到任务内存统计数组taskMemstats。 + +接下来,代码将usedSize参数累加到对应任务的memUsed字段上,表示该任务使用的内存增加了usedSize字节。然后使用MAX_MEM_USE宏更新该任务的内存峰值,即将当前的memUsed值与memPeak进行比较,取较大值作为新的memPeak值。 + +最后,代码将usedSize参数累加到整体内存统计信息stat的memTotalUsed字段上,表示系统整体使用的内存增加了usedSize字节。同样地,使用MAX_MEM_USE宏更新整体内存的峰值。 + +这段代码的作用是在任务执行过程中,根据实际使用的内存大小更新任务和整体的内存统计信息。*/ LITE_OS_SEC_TEXT_MINOR VOID OsMemstatTaskUsedInc(Memstat *stat, UINT32 usedSize, UINT32 taskId) { UINT32 record = MIN_TASK_ID(taskId, TASK_NUM - 1); @@ -51,6 +60,13 @@ LITE_OS_SEC_TEXT_MINOR VOID OsMemstatTaskUsedInc(Memstat *stat, UINT32 usedSize, stat->memTotalPeak = MAX_MEM_USE(stat->memTotalPeak, stat->memTotalUsed); } +/*这段代码是一个函数OsMemstatTaskUsedDec的实现,用于更新内存统计信息。 + +代码首先获取任务ID的最小值,确保不越界。然后通过stat参数获取到任务内存统计数组taskMemstats。 + +接下来,代码判断当前任务使用的内存是否小于要释放的内存usedSize,如果是,则打印一条信息并直接返回。否则,将usedSize从对应任务的memUsed字段上减去,表示该任务使用的内存减少了usedSize字节。然后将usedSize从整体内存统计信息stat的memTotalUsed字段上减去,表示系统整体使用的内存减少了usedSize字节。 + +这段代码的作用是在任务执行过程中,根据实际释放的内存大小更新任务和整体的内存统计信息。如果当前任务使用的内存小于要释放的内存大小,则说明存在内存释放错误,打印一条信息以便调试。*/ LITE_OS_SEC_TEXT_MINOR VOID OsMemstatTaskUsedDec(Memstat *stat, UINT32 usedSize, UINT32 taskId) { UINT32 record = MIN_TASK_ID(taskId, TASK_NUM - 1); @@ -66,6 +82,15 @@ LITE_OS_SEC_TEXT_MINOR VOID OsMemstatTaskUsedDec(Memstat *stat, UINT32 usedSize, stat->memTotalUsed -= usedSize; } +/*这段代码是一个函数OsMemstatTaskClear的实现,用于清除任务的内存统计信息。 + +代码首先获取任务ID的最小值,确保不越界。然后通过stat参数获取到任务内存统计数组taskMemstats。 + +接下来,代码判断当前任务使用的内存是否为0,如果不为0,则打印一条信息,说明在删除任务时该任务仍有未释放的内存。 + +然后,将对应任务的memUsed字段和memPeak字段都设置为0,表示清除该任务的内存使用和内存峰值记录。 + +这段代码的作用是在删除任务时,清除该任务的内存统计信息,并在必要时打印警告信息以提醒开发者注意内存释放的完整性。*/ LITE_OS_SEC_TEXT_MINOR VOID OsMemstatTaskClear(Memstat *stat, UINT32 taskId) { UINT32 record = MIN_TASK_ID(taskId, TASK_NUM - 1); @@ -80,6 +105,13 @@ LITE_OS_SEC_TEXT_MINOR VOID OsMemstatTaskClear(Memstat *stat, UINT32 taskId) taskMemstats[record].memPeak = 0; } +/*这段代码是一个函数OsMemstatTaskUsage的实现,用于获取指定任务的内存使用量。 + +代码首先获取任务ID的最小值,确保不越界。然后通过stat参数获取到任务内存统计数组taskMemstats。 + +接下来,代码返回指定任务的memUsed字段,即该任务当前使用的内存量。 + +这段代码的作用是获取指定任务的内存使用量,可以用于监控和调试任务的内存消耗情况。*/ LITE_OS_SEC_TEXT_MINOR UINT32 OsMemstatTaskUsage(const Memstat *stat, UINT32 taskId) { UINT32 record = MIN_TASK_ID(taskId, TASK_NUM - 1); @@ -88,6 +120,17 @@ LITE_OS_SEC_TEXT_MINOR UINT32 OsMemstatTaskUsage(const Memstat *stat, UINT32 tas return taskMemstats[record].memUsed; } +/*这段代码是一个函数OsMemTaskUsage的实现,用于获取指定任务在系统内所有内存池中的内存使用量之和。 + +首先,代码定义了两个指针变量pool和stat,用于存储内存池信息和内存统计信息。 + +然后,通过判断是否开启了多内存池支持,分别处理单内存池和多内存池的情况。 + +如果未开启多内存池支持,则直接获取系统内存池的内存统计信息stat。最后,调用OsMemstatTaskUsage函数获取指定任务在该内存池中的内存使用量,并返回结果。 + +如果开启了多内存池支持,则需要遍历所有内存池,将每个内存池中指定任务的内存使用量累加起来,最终返回总和。 + +这段代码的作用是获取指定任务在系统内所有内存池中的内存使用量之和,可以用于监控和调试系统内存的消耗情况。*/ UINT32 OsMemTaskUsage(UINT32 taskId) { LosMemPoolInfo *pool = NULL; @@ -110,6 +153,17 @@ UINT32 OsMemTaskUsage(UINT32 taskId) #endif } +/*这段代码是一个函数OsMemTaskClear的实现,用于清除指定任务在系统内所有内存池中的内存统计信息。 + +首先,代码定义了两个指针变量pool和stat,用于存储内存池信息和内存统计信息。 + +然后,通过判断是否开启了多内存池支持,分别处理单内存池和多内存池的情况。 + +如果未开启多内存池支持,则直接获取系统内存池的内存统计信息stat。最后,调用OsMemstatTaskClear函数清除指定任务在该内存池中的内存统计信息。 + +如果开启了多内存池支持,则需要遍历所有内存池,依次获取每个内存池的内存统计信息,并调用OsMemstatTaskClear函数清除指定任务在每个内存池中的内存统计信息。 + +这段代码的作用是清除指定任务在系统内所有内存池中的内存统计信息,可以用于在删除任务时释放相关的内存统计记录,以确保内存统计信息的准确性。*/ VOID OsMemTaskClear(UINT32 taskId) { LosMemPoolInfo *pool = NULL; diff --git a/src/kernel/base/mem/common/multipool/los_multipool.c b/src/kernel/base/mem/common/multipool/los_multipool.c index c4c8e33..d50caa8 100644 --- a/src/kernel/base/mem/common/multipool/los_multipool.c +++ b/src/kernel/base/mem/common/multipool/los_multipool.c @@ -30,6 +30,17 @@ STATIC VOID *g_poolHead = NULL; +/*这段代码是一个函数OsMemMulPoolInit的实现,用于初始化多内存池。 + +首先,代码定义了几个变量,包括nextPool、curPool和poolEnd。其中,nextPool和curPool用于遍历内存池链表,poolEnd用于计算内存池的结束地址。 + +然后,通过循环遍历内存池链表,检查新的内存池是否与已有的内存池冲突。如果发现冲突,则输出错误信息并返回错误码。 + +接着,根据内存池链表的状态,将新的内存池插入到链表的末尾或者作为链表的头节点。 + +最后,设置新的内存池的下一个内存池指针为NULL,并返回成功的状态码。 + +这段代码的作用是初始化多内存池,将新的内存池插入到内存池链表中,并确保各个内存池之间没有冲突。多内存池的使用可以提供更灵活的内存管理能力,方便系统对不同类型的内存进行分配和释放。*/ UINT32 OsMemMulPoolInit(VOID *pool, UINT32 size) { VOID *nextPool = g_poolHead; @@ -58,6 +69,21 @@ UINT32 OsMemMulPoolInit(VOID *pool, UINT32 size) return LOS_OK; } +/*这段代码是一个函数OsMemMulPoolDeinit的实现,用于反初始化多内存池。 + +首先,代码定义了几个变量,包括ret、nextPool和curPool。其中,ret用于保存函数执行结果,nextPool和curPool用于遍历内存池链表。 + +然后,通过一个do-while循环的结构来执行具体的反初始化操作。 + +在循环中,首先检查传入的内存池指针是否为空,如果为空则直接退出循环。 + +接着,判断传入的内存池是否为链表的头节点。如果是头节点,则将链表的头指针指向下一个内存池,并返回成功的状态码。 + +如果不是头节点,则遍历内存池链表,寻找与传入的内存池指针相等的节点。一旦找到对应的节点,将前一个节点的next指针指向下一个节点,并返回成功的状态码。 + +最后,循环结束后,返回执行结果。 + +这段代码的作用是反初始化多内存池,从内存池链表中移除指定的内存池,并释放相关的资源。反初始化操作可以根据需要动态地增加或删除内存池,以适应系统的内存管理需求的变化。*/ UINT32 OsMemMulPoolDeinit(const VOID *pool) { UINT32 ret = LOS_NOK; @@ -90,12 +116,29 @@ UINT32 OsMemMulPoolDeinit(const VOID *pool) return ret; } +/*这段代码是函数OsMemMulPoolHeadGet的实现,用于获取多内存池链表的头节点指针。 +代码很简单,直接返回全局变量g_poolHead,该变量保存了多内存池链表的头节点指针。 + +调用这个函数可以方便地获取多内存池链表的头节点地址,以便后续进行其他操作,比如对内存池进行遍历、查询或者修改等。*/ VOID *OsMemMulPoolHeadGet(VOID) { return g_poolHead; } +/*这段代码是函数LOS_MemDeInit的实现,用于释放指定内存池的资源并进行反初始化操作。 + +首先,代码定义了几个变量,包括ret和intSave。其中,ret用于保存函数执行结果,intSave用于保存中断状态。 + +接下来,通过调用MEM_LOCK函数保存中断状态,以确保在执行反初始化操作期间不会被中断打断。 + +然后,调用OsMemMulPoolDeinit函数对指定的内存池进行反初始化操作,将返回结果保存到ret中。 + +最后,通过调用MEM_UNLOCK函数恢复之前保存的中断状态。 + +最终,返回执行结果。 + +这段代码的作用是释放指定内存池的资源,并执行反初始化操作。在释放内存池之前,使用MEM_LOCK函数保存中断状态,避免在释放内存池期间被中断打断,然后通过调用OsMemMulPoolDeinit函数执行反初始化操作。最后,使用MEM_UNLOCK函数恢复之前保存的中断状态。这样可以确保在释放内存池的过程中,不会发生竞态条件或者资源冲突的问题。*/ LITE_OS_SEC_TEXT_INIT UINT32 LOS_MemDeInit(VOID *pool) { UINT32 ret; @@ -108,6 +151,17 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_MemDeInit(VOID *pool) return ret; } +/*这段代码是函数LOS_MemPoolList的实现,用于打印多内存池链表中每个内存池的信息。 + +首先,代码定义了两个变量,包括nextPool和index。其中,nextPool用于保存下一个内存池的指针,index用于记录内存池的数量。 + +然后,通过一个while循环遍历多内存池链表,对每个内存池调用OsMemInfoPrint函数进行信息输出,并更新nextPool和index。 + +在循环中,先输出当前内存池的编号,然后调用OsMemInfoPrint函数输出该内存池的相关信息。 + +最后,返回内存池的数量。 + +这段代码的作用是打印多内存池链表中每个内存池的信息,便于开发人员进行调试和管理。通过遍历内存池链表,可以获取每个内存池的地址,并使用OsMemInfoPrint函数将内存池的相关信息输出到控制台上。同时,还可以统计内存池的数量,以便对内存池进行更精细的管理。*/ LITE_OS_SEC_TEXT_INIT UINT32 LOS_MemPoolList(VOID) { VOID *nextPool = g_poolHead;