当前位置: 首页 > news >正文

郑州做网站zzmshl网店网络营销策划方案

郑州做网站zzmshl,网店网络营销策划方案,正能量视频免费网站免下载,网站的建设模式是指什么时候开始内存管理模块管理系统的内存资源#xff0c;它是操作系统的核心模块之一#xff0c;主要包括内存的初始化、分配以及释放。 在系统运行过程中#xff0c;内存管理模块通过对内存的申请/释放来管理用户和OS对内存的使用#xff0c;使内存的利用率和使用效率达到最优#x…内存管理模块管理系统的内存资源它是操作系统的核心模块之一主要包括内存的初始化、分配以及释放。 在系统运行过程中内存管理模块通过对内存的申请/释放来管理用户和OS对内存的使用使内存的利用率和使用效率达到最优同时最大限度地解决系统的内存碎片问题。 鸿蒙轻内核的内存管理分为静态内存管理和动态内存管理提供内存初始化、分配、释放等功能。 动态内存在动态内存池中分配用户指定大小的内存块。 优点按需分配。缺点内存池中可能出现碎片。 静态内存在静态内存池中分配用户初始化时预设固定大小的内存块。 优点分配和释放效率高静态内存池中无碎片。缺点只能申请到初始化预设大小的内存块不能按需申请。 上一系列分析了静态内存我们开始分析动态内存。动态内存管理主要用于用户需要使用大小不等的内存块的场景。当用户需要使用内存时可以通过操作系统的动态内存申请函数索取指定大小的内存块一旦使用完毕通过动态内存释放函数归还所占用内存使之可以重复使用。 OpenHarmony LiteOS-M动态内存在TLSF算法的基础上对区间的划分进行了优化获得更优的性能降低了碎片率。动态内存核心算法框图如下 根据空闲内存块的大小使用多个空闲链表来管理。根据内存空闲块大小分为两个部分[4, 127]和[2^7, 2^31]如上图size class所示 对[4,127]区间的内存进行等分如上图绿色部分所示分为31个小区间每个小区间对应内存块大小为4字节的倍数。每个小区间对应一个空闲内存链表和用于标记对应空闲内存链表是否为空的一个比特位值为1时空闲链表非空。[4,127]区间的内存使用1个32位无符号整数位图标记。 大于127字节的空闲内存块按照2的次幂区间大小进行空闲链表管理。总共分为24个小区间每个小区间又等分为8个二级小区间见上图蓝色的Size Class和Size SubClass部分。每个二级小区间对应一个空闲链表和用于标记对应空闲内存链表是否为空的一个比特位。总共24*8192个二级小区间对应192个空闲链表和192/326个32位无符号整数位图标记。 例如当有40字节的空闲内存需要插入空闲链表时对应小区间[40,43]第10个空闲链表位图标记的第10比特位。把40字节的空闲内存挂载第10个空闲链表上并判断是否需要更新位图标记。当需要申请40字节的内存时根据位图标记获取存在满足申请大小的内存块的空闲链表从空闲链表上获取空闲内存节点。如果分配的节点大于需要申请的内存大小进行分割节点操作剩余的节点重新挂载到相应的空闲链表上。当有580字节的空闲内存需要插入空闲链表时对应二级小区间[2^9, 2^9 2^6]第312*847个空闲链表第2个位图标记的第17比特位。把580字节的空闲内存挂载第47个空闲链表上并判断是否需要更新位图标记。当需要申请580字节的内存时根据位图标记获取存在满足申请大小的内存块的空闲链表从空闲链表上获取空闲内存节点。如果分配的节点大于需要申请的内存大小进行分割节点操作剩余的节点重新挂载到相应的空闲链表上。如果对应的空闲链表为空则向更大的内存区间去查询是否有满足条件的空闲链表实际计算时会一次性查找到满足申请大小的空闲链表。 动态内存管理结构如下图所示 内存池池头部分 内存池池头部分包含内存池信息和位图标记数组和空闲链表数组。内存池信息包含内存池起始地址及堆区域总大小内存池属性。位图标记数组有7个32位无符号整数组成每个比特位标记对应的空闲链表是否挂载空闲内存块节点。空闲内存链表包含223个空闲内存头节点信息每个空闲内存头节点信息维护内存节点头和空闲链表中的前驱、后继空闲内存节点。 内存池节点部分 包含3种类型节点未使用空闲内存节点已使用内存节点尾节点。每个内存节点维护一个前序指针指向内存池中上一个内存节点维护大小和使用标记标记该内存节点的大小和是否使用等。空闲内存节点和已使用内存节点后面的数据域尾节点没有数据域。 本文通过分析动态内存模块的源码帮助读者掌握动态内存的使用。本文中所涉及的源码以OpenHarmony LiteOS-M内核为例均可以在开源站点 https://gitee.com/openharmony/kernel_liteos_m 获取。接下来我们看下动态内存的结构体动态内存初始化动态内存常用操作的源代码。 1、动态内存结构体定义和常用宏定义 1.1 动态内存结构体定义 动态内存的结构体有动态内存池信息结构体OsMemPoolInfo动态内存池头结构体OsMemPoolHead、动态内存节点头结构体OsMemNodeHead已使用内存节点结构体OsMemUsedNodeHead空闲内存节点结构体OsMemFreeNodeHead。这些结构体定义在文件kernel\src\mm\los_memory.c中下文会结合上文的动态内存管理结构示意图对各个结构体的成员变量进行说明。 1.1.1 动态内存池池头相关结构体 动态内存池信息结构体OsMemPoolInfo维护内存池的开始地址和大小信息。三个主要的成员是内存池开始地址.pool内存池大小.poolSize和内存值属性.attr。如果开启宏LOSCFG_MEM_WATERLINE还会维护内存池的水线数值。 struct OsMemPoolInfo {VOID *pool; /* 内存池的内存开始地址 */UINT32 totalSize; /* 内存池总大小 */UINT32 attr; /* 内存池属性 */ #if (LOSCFG_MEM_WATERLINE 1)UINT32 waterLine; /* 内存池中内存最大使用值 */UINT32 curUsedSize; /* 内存池中当前已使用的大小 */ #endif };动态内存池头结构体OsMemPoolHead源码如下除了动态内存池信息结构体struct OsMemPoolInfo info还维护2个数组一个是空闲内存链表位图数组freeListBitmap[]一个是空闲内存链表数组freeList[]。宏定义OS_MEM_BITMAP_WORDS和OS_MEM_FREE_LIST_COUNT后文会介绍。 struct OsMemPoolHead {struct OsMemPoolInfo info;UINT32 freeListBitmap[OS_MEM_BITMAP_WORDS];struct OsMemFreeNodeHead *freeList[OS_MEM_FREE_LIST_COUNT]; #if (LOSCFG_MEM_MUL_POOL 1)VOID *nextPool; #endif };1.1.2 动态内存池内存节点相关结构体 先看下动态内存节点头结构体OsMemNodeHead的定义⑴处如果开启内存节点完整性检查的宏LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK会维护魔术字.magic进行校验。⑵处如果开启内存泄漏检查的宏会维护链接寄存器数组linkReg[]。⑶处的成员变量是个指针组合体内存池中的每个内存节点头维护指针执行上一个内存节点。⑷处维护内存节点的大小和标记信息。 struct OsMemNodeHead {#if (LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK 1) ⑴ UINT32 magic;#endif#if (LOSCFG_MEM_LEAKCHECK 1) ⑵ UINTPTR linkReg[LOSCFG_MEM_RECORD_LR_CNT];#endifunion {struct OsMemNodeHead *prev; /* The prev is used for current node points to the previous node */struct OsMemNodeHead *next; /* The next is used for sentinel node points to the expand node */ ⑶ } ptr;#if (LOSCFG_MEM_FREE_BY_TASKID 1) ⑷ UINT32 taskID : 6;UINT32 sizeAndFlag : 26;#elseUINT32 sizeAndFlag;#endif};接着看下已使用内存节点结构体OsMemUsedNodeHead该结构体比较简单直接以动态内存节点头结构体OsMemNodeHead作为唯一的成员。 struct OsMemUsedNodeHead {struct OsMemNodeHead header; };我们再看下空闲内存节点结构体OsMemFreeNodeHead除了动态内存节点头结构体OsMemNodeHead成员还包含2个指针分别指向上一个和下一个空闲内存节点。 struct OsMemFreeNodeHead {struct OsMemNodeHead header;struct OsMemFreeNodeHead *prev;struct OsMemFreeNodeHead *next; };1.2 动态内存核心算法相关的宏和函数 动态内存中还提供了一些和TLSF算法相关的宏定义和内联函数这些宏非常重要在分析源代码前需要熟悉下这些宏的定义。可以结合上文的动态内存核心算法框图进行学习。⑴处的宏对处于[2n,2(n1)]其中n7,8…30区间的大内存块进行2^38等分。⑵处的宏定义处于[4,127]区间的小内存块划分为31个即4,8,12…124。⑶处定义小内存的上界值考虑内存对齐和粒度最大值只能取到124。 ⑷处的宏表示处于[2n,2(n1)]其中n7,8…30区间的大内存分为24个小区间其中n7 就是⑺处定义的宏OS_MEM_LARGE_START_BUCKET。⑻处对应空闲内存链表的长度。⑼处是空闲链表位图数组的长度31个小内存使用1个位图字所以需要加1。⑽处定义位图掩码每个位图字是32位无符号整数。 继续看下内联函数。⑾处函数查找位图字中的第一个1的比特位这个实现的功能类似内建函数__builtin_ctz。该函数用于获取空闲内存链表对应的位图字中第一个挂载着空闲内存块的空闲内存链表。⑿处获取位图字中的最后一个1的比特位(从32位二进制数值从左到右依次第0,1,…,31位)。⒀处函数名称中的Log是对数英文logarithm的缩写函数用于计算以2为底的对数的整数部分。⒁处获取内存区间的大小级别编号对于小于128字节的有31个级别对处于[2n,2(n1)]其中n7,8…30区间的内存有24个级别。⒂处根据内存大小内存区间一级编号获取获取二级小区间的编号对处于[2n,2(n1)]其中n7,8…30区间的内存有8个二级小区间。 /* The following is the macro definition and interface implementation related to the TLSF. *//* Supposing a Second Level Index: SLI 3\. */ ⑴ #define OS_MEM_SLI 3/* Giving 1 free list for each small bucket: 4, 8, 12, up to 124\. */ ⑵ #define OS_MEM_SMALL_BUCKET_COUNT 31 ⑶ #define OS_MEM_SMALL_BUCKET_MAX_SIZE 128/* Giving 2^OS_MEM_SLI free lists for each large bucket. */ ⑷ #define OS_MEM_LARGE_BUCKET_COUNT 24/* OS_MEM_SMALL_BUCKET_MAX_SIZE to the power of 2 is 7\. */ ⑺ #define OS_MEM_LARGE_START_BUCKET 7/* The count of free list. */ ⑻ #define OS_MEM_FREE_LIST_COUNT (OS_MEM_SMALL_BUCKET_COUNT (OS_MEM_LARGE_BUCKET_COUNT OS_MEM_SLI))/* The bitmap is used to indicate whether the free list is empty, 1: not empty, 0: empty. */ ⑼ #define OS_MEM_BITMAP_WORDS ((OS_MEM_FREE_LIST_COUNT 5) 1)⑽ #define OS_MEM_BITMAP_MASK 0x1FU/* Used to find the first bit of 1 in bitmap. */ ⑾ STATIC INLINE UINT16 OsMemFFS(UINT32 bitmap){bitmap ~bitmap 1;return (OS_MEM_BITMAP_MASK - CLZ(bitmap));}/* Used to find the last bit of 1 in bitmap. */ ⑿ STATIC INLINE UINT16 OsMemFLS(UINT32 bitmap){return (OS_MEM_BITMAP_MASK - CLZ(bitmap));}⒀ STATIC INLINE UINT32 OsMemLog2(UINT32 size){return (size 0) ? OsMemFLS(size) : 0;}/* Get the first level: f log2(size). */ ⒁ STATIC INLINE UINT32 OsMemFlGet(UINT32 size){if (size OS_MEM_SMALL_BUCKET_MAX_SIZE) {return ((size 2) - 1); /* 2: The small bucket setup is 4\. */}return (OsMemLog2(size) - OS_MEM_LARGE_START_BUCKET OS_MEM_SMALL_BUCKET_COUNT);}/* Get the second level: s (size - 2^f) * 2^SLI / 2^f. */ ⒂ STATIC INLINE UINT32 OsMemSlGet(UINT32 size, UINT32 fl){if ((fl OS_MEM_SMALL_BUCKET_COUNT) || (size OS_MEM_SMALL_BUCKET_MAX_SIZE)) {PRINT_ERR(fl or size is too small, fl %u, size %u\n, fl, size);return 0;}UINT32 sl (size OS_MEM_SLI) (fl - OS_MEM_SMALL_BUCKET_COUNT OS_MEM_LARGE_START_BUCKET);return (sl - (1 OS_MEM_SLI));}2、动态内存常用操作 动态内存管理模块为用户提供初始化和删除内存池、申请、释放动态内存等操作我们来分析下接口的源代码。在分析下内存操作接口之前我们先看下一下常用的内部接口。 2.1 动态内存内部接口 2.1.1 设置和清理空闲内存链表标记位 ⑴处函数OsMemSetFreeListBit需要2个参数一个是内存池池头head一个是空闲内存链表索引index。当空闲内存链表上挂载有空闲内存块时位图字相应的位需要设置为1。⑴处函数OsMemClearFreeListBit做相反的操作当空闲内存链表上不再挂载空闲内存块时需要对应的比特位清零。 STATIC INLINE VOID OsMemSetFreeListBit(struct OsMemPoolHead *head, UINT32 index){ ⑴ head-freeListBitmap[index 5] | 1U (index 0x1f);}STATIC INLINE VOID OsMemClearFreeListBit(struct OsMemPoolHead *head, UINT32 index){ ⑵ head-freeListBitmap[index 5] ~(1U (index 0x1f));}2.1.2 合并内存节点 函数VOID OsMemMergeNode(struct OsMemNodeHead *node)用于合并给定节点struct OsMemNodeHead *node和它前一个空闲节点。⑴处把前一个节点的大小加上要合入节点的大小。⑵处获取给定节点的下一个节点然后执行⑶把它的前一个节点指向给定节点的前一个节点完成节点的合并。其中宏OS_MEM_NODE_GET_LAST_FLAG用于判断是否最后一个节点默认为0可以自行查看下该宏的定义。 STATIC INLINE VOID OsMemMergeNode(struct OsMemNodeHead *node) {struct OsMemNodeHead *nextNode NULL;⑴ node-ptr.prev-sizeAndFlag node-sizeAndFlag; ⑵ nextNode (struct OsMemNodeHead *)((UINTPTR)node node-sizeAndFlag);if (!OS_MEM_NODE_GET_LAST_FLAG(nextNode-sizeAndFlag)) { ⑶ nextNode-ptr.prev node-ptr.prev;} }2.1.3 分割内存节点 函数VOID OsMemSplitNode(VOID *pool, struct OsMemNodeHead *allocNode, UINT32 allocSize)用于分割内存节点需要三个参数。VOID *pool是内存池起始地址struct OsMemNodeHead *allocNode表示从该内存节点分配出需要的内存UINT32 allocSize是需要分配的内存大小。分割之后剩余的部分如果下一个节点是空闲节点则合并一起。分割剩余的节点会挂载到空闲内存链表上。 ⑴处表示newFreeNode是分配之后剩余的空闲内存节点设置它的上一个节点为分配的节点并设置剩余内存大小。⑵处调整分配内存的大小⑶处获取下一个节点然后执行⑷下一个节点的前一个节点设置为新的空闲节点newFreeNode。⑸处判断下一个节点是否被使用如果没有使用则把下一个节点从链表中删除然后和空闲节点newFreeNode合并。⑹处分割剩余的空闲内存节点挂载到链表上。 STATIC INLINE VOID OsMemSplitNode(VOID *pool, struct OsMemNodeHead *allocNode, UINT32 allocSize) {struct OsMemFreeNodeHead *newFreeNode NULL;struct OsMemNodeHead *nextNode NULL;⑴ newFreeNode (struct OsMemFreeNodeHead *)(VOID *)((UINT8 *)allocNode allocSize);newFreeNode-header.ptr.prev allocNode;newFreeNode-header.sizeAndFlag allocNode-sizeAndFlag - allocSize; ⑵ allocNode-sizeAndFlag allocSize; ⑶ nextNode OS_MEM_NEXT_NODE(newFreeNode-header);if (!OS_MEM_NODE_GET_LAST_FLAG(nextNode-sizeAndFlag)) { ⑷ nextNode-ptr.prev newFreeNode-header;if (!OS_MEM_NODE_GET_USED_FLAG(nextNode-sizeAndFlag)) { ⑸ OsMemFreeNodeDelete(pool, (struct OsMemFreeNodeHead *)nextNode);OsMemMergeNode(nextNode);}}⑹ OsMemFreeNodeAdd(pool, newFreeNode); }2.1.4 重新申请内存 OsMemReAllocSmaller()函数用于从一个大的内存块里重新申请一个较小的内存他需要的4个参数分别是VOID *pool是内存池起始地址UINT32 allocSize是重新申请的内存的大小struct OsMemNodeHead *node是当前需要重新分配内存的内存节点UINT32 nodeSize是当前节点的大小。⑴设置内存节点selfNode.sizeAndFlag为去除标记后的实际大小⑵按需分割节点⑶分割后的节点设置已使用标记完成完成申请内存。 STATIC INLINE VOID OsMemReAllocSmaller(VOID *pool, UINT32 allocSize, struct OsMemNodeHead *node, UINT32 nodeSize) { #if (LOSCFG_MEM_WATERLINE 1)struct OsMemPoolHead *poolInfo (struct OsMemPoolHead *)pool; #endif ⑴ node-sizeAndFlag nodeSize;if ((allocSize OS_MEM_MIN_LEFT_SIZE) nodeSize) { ⑵ OsMemSplitNode(pool, node, allocSize); #if (LOSCFG_MEM_WATERLINE 1)poolInfo-info.curUsedSize - nodeSize - allocSize; #endif} ⑶ OS_MEM_NODE_SET_USED_FLAG(node-sizeAndFlag); #if (LOSCFG_MEM_LEAKCHECK 1)OsMemLinkRegisterRecord(node); #endif }2.1.5 合并节点重新申请内存 最后再来看下函数函数OsMemMergeNodeForReAllocBigger()用于合并内存节点重新分配更大的内存空间。它需要5个参数VOID *pool是内存池起始地址UINT32 allocSize是重新申请的内存的大小struct OsMemNodeHead *node是当前需要重新分配内存的内存节点UINT32 nodeSize是当前节点的大小struct OsMemNodeHead *nextNode是下一个内存节点。⑴处设置内存节点的大小为去除标记后的实际大小⑵把下一个节点从链表上删除然后合并节点。⑶处如果合并后的节点大小超过需要重新分配的大小则分割节点。⑷处把申请的内存节点标记为已使用完成完成申请内存 STATIC INLINE VOID OsMemMergeNodeForReAllocBigger(VOID *pool, UINT32 allocSize, struct OsMemNodeHead *node,UINT32 nodeSize, struct OsMemNodeHead *nextNode) { ⑴ node-sizeAndFlag nodeSize; ⑵ OsMemFreeNodeDelete(pool, (struct OsMemFreeNodeHead *)nextNode);OsMemMergeNode(nextNode);if ((allocSize OS_MEM_MIN_LEFT_SIZE) node-sizeAndFlag) { ⑶ OsMemSplitNode(pool, node, allocSize);} ⑷ OS_MEM_NODE_SET_USED_FLAG(node-sizeAndFlag);OsMemWaterUsedRecord((struct OsMemPoolHead *)pool, node-sizeAndFlag - nodeSize); #if (LOSCFG_MEM_LEAKCHECK 1)OsMemLinkRegisterRecord(node); #endif }2.1.6 空闲内存链表相关操作 动态内存提供了针对空闲内存链表的几个操作我们依次分析下这些操作的代码。首先看下函数OsMemFreeListIndexGet根据内存节点大小获取空闲内存链表的索引。⑴处先获取一级索引⑵处获取二级索引然后计算空闲链表的索引并返回。 STATIC INLINE UINT32 OsMemFreeListIndexGet(UINT32 size) { ⑴ UINT32 fl OsMemFlGet(size);if (fl OS_MEM_SMALL_BUCKET_COUNT) {return fl;}⑵ UINT32 sl OsMemSlGet(size, fl);return (OS_MEM_SMALL_BUCKET_COUNT ((fl - OS_MEM_SMALL_BUCKET_COUNT) OS_MEM_SLI) sl); }接着看下函数OsMemListAdd如何把空闲内存节点插入空闲内存链表。⑴处获取空闲链表的第一个节点如果节点不为空则把这个节点的前驱节点设置为待插入节点node。⑵处设置待插入节点的前驱、后继节点然后把该节点赋值给空闲链表pool-freeList[listIndex]。最后执行⑶处代码把设置空闲链表位图字并设置魔术字。 STATIC INLINE VOID OsMemListAdd(struct OsMemPoolHead *pool, UINT32 listIndex, struct OsMemFreeNodeHead *node) { ⑴ struct OsMemFreeNodeHead *firstNode pool-freeList[listIndex];if (firstNode ! NULL) {firstNode-prev node;} ⑵ node-prev NULL;node-next firstNode;pool-freeList[listIndex] node; ⑶ OsMemSetFreeListBit(pool, listIndex);OS_MEM_SET_MAGIC(node-header); }最后分析下函数OsMemListDelete如何从空闲内存链表删除指定的空闲内存节点。⑴处如果删除的节点是空闲内存链表的第一个节点则需要把空闲链表执行待删除节点的下一个节点。如果下一个节点为空需要执行⑵清除空闲链表的位图字。否则执行⑶把下一个节点的前驱节点设置为空。如果待删除节点不是空闲链表的第一个节点执行⑷把待删除节点的前驱节点的后续节点设置为待删除节点的后继节点。如果待删除节点不为最后一个节点需要执行⑸把待删除节点的后继节点的前驱节点设置为待删除节点的前驱节点。最后需要设置下魔术字。 STATIC INLINE VOID OsMemListDelete(struct OsMemPoolHead *pool, UINT32 listIndex, struct OsMemFreeNodeHead *node) { ⑴ if (node pool-freeList[listIndex]) {pool-freeList[listIndex] node-next;if (node-next NULL) { ⑵ OsMemClearFreeListBit(pool, listIndex);} else { ⑶ node-next-prev NULL;}} else { ⑷ node-prev-next node-next;if (node-next ! NULL) { ⑸ node-next-prev node-prev;}}OS_MEM_SET_MAGIC(node-header); }2.1.7 空闲内存节点相关操作 动态内存提供了针对空闲内存的几个操作如OsMemFreeNodeAdd、OsMemFreeNodeDelete、OsMemFreeNodeGet。 函数OsMemFreeNodeAdd用于把一个空闲内存节点加入相应的空闲内存链表上。⑴处调用函数获取空闲内存链表的索引然后执行⑵把空闲内存节点加入空闲链表。 STATIC INLINE VOID OsMemFreeNodeAdd(VOID *pool, struct OsMemFreeNodeHead *node) { ⑴ UINT32 index OsMemFreeListIndexGet(node-header.sizeAndFlag);if (index OS_MEM_FREE_LIST_COUNT) {LOS_Panic(The index of free lists is error, index %u\n, index);} ⑵ OsMemListAdd(pool, index, node); }函数OsMemFreeNodeDelete用于把一个空闲内存节点从相应的空闲内存链表上删除。代码较简单获取空闲内存链表的索引然后调用函数OsMemListDelete进行删除。 STATIC INLINE VOID OsMemFreeNodeDelete(VOID *pool, struct OsMemFreeNodeHead *node) {UINT32 index OsMemFreeListIndexGet(node-header.sizeAndFlag);OsMemListDelete(pool, index, node); }函数OsMemFreeNodeGet根据内存池地址和需要的内存大小获取满足大小条件的空闲内存块。⑴处调用函数获取满足大小条件的内存块然后执行⑵把获取到的内存块从空闲内存链表删除返回内存节点地址。 STATIC INLINE struct OsMemNodeHead *OsMemFreeNodeGet(VOID *pool, UINT32 size) {struct OsMemPoolHead *poolHead (struct OsMemPoolHead *)pool;UINT32 index; ⑴ struct OsMemFreeNodeHead *firstNode OsMemFindNextSuitableBlock(pool, size, index);if (firstNode NULL) {return NULL;}⑵ OsMemListDelete(poolHead, index, firstNode);return firstNode-header; }最后分析下函数OsMemFindNextSuitableBlock。⑴处根据需要的内存块大小获取一级区间编号如果申请的内存处于[4,127]区间执行⑵处记录空闲内存链表索引。如果需要申请的是大内存执行⑶处代码。先获取二级区间索引然后计算出空闲内存链表的索引值index。这样计算出来的空闲内存链表下可能并没有挂载空闲内存块调用⑷处函数OsMemNotEmptyIndexGet获取挂载空闲内存块的空闲内存链表索引值。如果成功获取到满足大小的空闲内存块返回空闲链表索引值否则继续执行后续代码。⑹处对空闲链表位图字进行遍历循环中的自增变量index对应一级区间编号。如果位图字不为空执行⑺获取这个位图字对应的最大的空闲内存链表的索引。 如果执行到⑻处说明没有匹配到合适的内存块返回空指针。⑼处表示存在满足大小的空闲内存链表调用函数OsMemFindCurSuitableBlock获取合适的内存块并返回。⑽处标签表示获取到合适的空闲内存链表索引返回空闲内存链表。 STATIC INLINE struct OsMemFreeNodeHead *OsMemFindNextSuitableBlock(VOID *pool, UINT32 size, UINT32 *outIndex) {struct OsMemPoolHead *poolHead (struct OsMemPoolHead *)pool; ⑴ UINT32 fl OsMemFlGet(size);UINT32 sl;UINT32 index, tmp;UINT32 curIndex OS_MEM_FREE_LIST_COUNT;UINT32 mask;do {if (fl OS_MEM_SMALL_BUCKET_COUNT) { ⑵ index fl;} else { ⑶ sl OsMemSlGet(size, fl);curIndex ((fl - OS_MEM_SMALL_BUCKET_COUNT) OS_MEM_SLI) sl OS_MEM_SMALL_BUCKET_COUNT;index curIndex 1;}⑷ tmp OsMemNotEmptyIndexGet(poolHead, index);if (tmp ! OS_MEM_FREE_LIST_COUNT) { ⑸ index tmp;goto DONE;}⑹ for (index LOS_Align(index 1, 32); index OS_MEM_FREE_LIST_COUNT; index 32) {mask poolHead-freeListBitmap[index 5]; /* 5: Divide by 32 to calculate the index of the bitmap array. */if (mask ! 0) { ⑺ index OsMemFFS(mask) index;goto DONE;}}} while (0);⑻ if (curIndex OS_MEM_FREE_LIST_COUNT) {return NULL;}⑼ *outIndex curIndex;return OsMemFindCurSuitableBlock(poolHead, curIndex, size); DONE:*outIndex index; ⑽ return poolHead-freeList[index]; }我们再详细分析下函数OsMemNotEmptyIndexGet的源码。⑴处根据空闲内存链表索引获取位图字⑵处判断空闲内存链表索引对应的一级内存区间对应的二级小内存区间是否存在满足条件的空闲内存块。其中index OS_MEM_BITMAP_MASK对索引只取低5位后可以把索引值和位图字中的比特位关联起来比如index为39时index OS_MEM_BITMAP_MASK等于7对应位图字的第7位。表达式~((1 (index OS_MEM_BITMAP_MASK)) - 1)则用于表示大于空闲内存链表索引index的索引值对应的位图字。⑵处的语句执行后mask就表示空闲链表索引值大于index的链表索引对应的位图字的值。当mask不为0时表示存在满足内存大小的空闲内存块则执行⑶处代码其中OsMemFFS(mask)获取位图字中第一个为1的比特位位数该位对应着挂载空闲内存块的链表。(index ~OS_MEM_BITMAP_MASK)对应链表索引的高位加上位图字位数就计算出挂载着满足申请条件的空闲内存链表的索引值。 STATIC INLINE UINT32 OsMemNotEmptyIndexGet(struct OsMemPoolHead *poolHead, UINT32 index) { ⑴ UINT32 mask poolHead-freeListBitmap[index 5]; /* 5: Divide by 32 to calculate the index of the bitmap array. */ ⑵ mask ~((1 (index OS_MEM_BITMAP_MASK)) - 1);if (mask ! 0) { ⑶ index OsMemFFS(mask) (index ~OS_MEM_BITMAP_MASK);return index;}return OS_MEM_FREE_LIST_COUNT; }最后再看下函数OsMemFindCurSuitableBlock。⑴处循环遍历空闲内存链表上挂载的内存块如果遍历到的内存块大小大于需要的大小则执行⑵返回该空闲内存块。否则返回空指针。 STATIC INLINE struct OsMemFreeNodeHead *OsMemFindCurSuitableBlock(struct OsMemPoolHead *poolHead,UINT32 index, UINT32 size) {struct OsMemFreeNodeHead *node NULL;⑴ for (node poolHead-freeList[index]; node ! NULL; node node-next) {if (node-header.sizeAndFlag size) { ⑵ return node;}}return NULL; }2.2 初始化动态内存池 我们分析下初始化动态内存池函数UINT32 LOS_MemInit(VOID *pool, UINT32 size)的代码。我们先看看函数参数VOID *pool是动态内存池的起始地址UINT32 size是初始化的动态内存池的总大小size需要小于等于*pool开始的内存区域的大小否则会影响后面的内存区域还需要大于动态内存池的最小值OS_MEM_MIN_POOL_SIZE。[pool, pool size]不能和其他内存池冲突。 我们看下代码⑴处对传入参数进行校验⑵处对传入参数进行是否内存对齐校验如果没有内存对齐会返回错误码。⑶处调用函数OsMemPoolInit()进行内存池初始化这是初始化内存的核心函数。⑷处开启宏LOSCFG_MEM_MUL_POOL多内存池支持时才会执行。 UINT32 LOS_MemInit(VOID *pool, UINT32 size) { ⑴ if ((pool NULL) || (size OS_MEM_MIN_POOL_SIZE)) {return OS_ERROR;}⑵ if (((UINTPTR)pool (OS_MEM_ALIGN_SIZE - 1)) || \(size (OS_MEM_ALIGN_SIZE - 1))) {PRINT_ERR(LiteOS heap memory address or size configured not aligned:address:0x%x,size:0x%x, alignsize:%d\n, \(UINTPTR)pool, size, OS_MEM_ALIGN_SIZE);return OS_ERROR;}⑶ if (OsMemPoolInit(pool, size)) {return OS_ERROR;}#if (LOSCFG_MEM_MUL_POOL 1) ⑷ if (OsMemPoolAdd(pool, size)) {(VOID)OsMemPoolDeinit(pool);return OS_ERROR;} #endif#if OS_MEM_TRACELOS_TraceReg(LOS_TRACE_MEM_TIME, OsMemTimeTrace, LOS_TRACE_MEM_TIME_NAME, LOS_TRACE_ENABLE);LOS_TraceReg(LOS_TRACE_MEM_INFO, OsMemInfoTrace, LOS_TRACE_MEM_INFO_NAME, LOS_TRACE_ENABLE); #endifOsHookCall(LOS_HOOK_TYPE_MEM_INIT, pool, size);return LOS_OK; }我们继续看下函数OsMemPoolInit()。⑴处设置动态内存池信息结构体struct OsMemPoolHead *poolHead的起始地址和大小⑵处设置内存池属性设置为锁定、不可扩展。⑶处获取内存池的第一个内存控制节点然后设置它的大小该节点大小等于内存池总大小减去内存池池头大小和一个内存节点头大小。然后再设置该内存节点的上一个节点为内存池的最后一个节点OS_MEM_END_NODE(pool, size)。 ⑷处调用宏给节点设置魔术字然后把内存节点插入到空闲内存链表中。⑸处获取内存池的尾节点设置魔术字然后执行⑹设置尾节点大小为0和设置上一个节点并设置已使用标记。如果开启调测宏LOSCFG_MEM_WATERLINE还会有些其他操作自行阅读即可。 STATIC UINT32 OsMemPoolInit(VOID *pool, UINT32 size) {struct OsMemPoolHead *poolHead (struct OsMemPoolHead *)pool;struct OsMemNodeHead *newNode NULL;struct OsMemNodeHead *endNode NULL;(VOID)memset_s(poolHead, sizeof(struct OsMemPoolHead), 0, sizeof(struct OsMemPoolHead));⑴ poolHead-info.pool pool;poolHead-info.totalSize size;poolHead-info.attr ~(OS_MEM_POOL_UNLOCK_ENABLE | OS_MEM_POOL_EXPAND_ENABLE); /* default attr: lock, not expand. */⑶ newNode OS_MEM_FIRST_NODE(pool);newNode-sizeAndFlag (size - sizeof(struct OsMemPoolHead) - OS_MEM_NODE_HEAD_SIZE);newNode-ptr.prev OS_MEM_END_NODE(pool, size); ⑷ OS_MEM_SET_MAGIC(newNode);OsMemFreeNodeAdd(pool, (struct OsMemFreeNodeHead *)newNode);/* The last mem node */ ⑸ endNode OS_MEM_END_NODE(pool, size);OS_MEM_SET_MAGIC(endNode); #if OS_MEM_EXPAND_ENABLEendNode-ptr.next NULL;OsMemSentinelNodeSet(endNode, NULL, 0); #else ⑹ endNode-sizeAndFlag 0;endNode-ptr.prev newNode;OS_MEM_NODE_SET_USED_FLAG(endNode-sizeAndFlag); #endif #if (LOSCFG_MEM_WATERLINE 1)poolHead-info.curUsedSize sizeof(struct OsMemPoolHead) OS_MEM_NODE_HEAD_SIZE;poolHead-info.waterLine poolHead-info.curUsedSize; #endifreturn LOS_OK; }2.3 申请动态内存 初始化动态内存池后我们可以使用函数VOID *LOS_MemAlloc(VOID *pool, UINT32 size)来申请动态内存下面分析下源码。 ⑴处对参数进行校验内存池地址不能为空申请的内存大小不能为0。⑵处判断申请的内存大小是否已标记为使用或内存对齐。⑶处调用函数OsMemAlloc(poolHead, size, intSave)申请内存块。 VOID *LOS_MemAlloc(VOID *pool, UINT32 size) { #if OS_MEM_TRACEUINT64 start HalClockGetCycles(); #endif⑴ if ((pool NULL) || (size 0)) {return NULL;}if (size OS_MEM_MIN_ALLOC_SIZE) {size OS_MEM_MIN_ALLOC_SIZE;}struct OsMemPoolHead *poolHead (struct OsMemPoolHead *)pool;VOID *ptr NULL;UINT32 intSave;MEM_LOCK(poolHead, intSave);do { ⑵ if (OS_MEM_NODE_GET_USED_FLAG(size) || OS_MEM_NODE_GET_ALIGNED_FLAG(size)) {break;} ⑶ ptr OsMemAlloc(poolHead, size, intSave);} while (0);MEM_UNLOCK(poolHead, intSave);#if OS_MEM_TRACEUINT64 end HalClockGetCycles();UINT32 timeUsed MEM_TRACE_CYCLE_TO_US(end - start);LOS_Trace(LOS_TRACE_MEM_TIME, (UINTPTR)pool MEM_POOL_ADDR_MASK, MEM_TRACE_MALLOC, timeUsed);LOS_MEM_POOL_STATUS poolStatus {0};(VOID)LOS_MemInfoGet(pool, poolStatus);UINT8 fragment 100 - poolStatus.maxFreeNodeSize * 100 / poolStatus.totalFreeSize; /* 100: percent denominator. */UINT8 usage LOS_MemTotalUsedGet(pool) * 100 / LOS_MemPoolSizeGet(pool); /* 100: percent denominator. */LOS_Trace(LOS_TRACE_MEM_INFO, (UINTPTR)pool MEM_POOL_ADDR_MASK, fragment, usage, poolStatus.totalFreeSize,poolStatus.maxFreeNodeSize, poolStatus.usedNodeNum, poolStatus.freeNodeNum); #endifOsHookCall(LOS_HOOK_TYPE_MEM_ALLOC, pool, size);return ptr; }我们继续分析函数OsMemAlloc()。⑴处对申请内存大小加上头结点大小的和进行内存对齐⑵处从空闲内存链表中获取一个满足申请大小的空闲内存块如果申请失败则打印错误信息。⑶处如果找到的内存块大于需要的内存大小则执行分割操作。⑷处把已分配的内存节点标记为已使用更新水线记录。⑸返回内存块的数据区的地址这个是通过内存节点地址加1定位到数据区内存地址实现的。申请内存完成调用申请内存的函数中可以使用申请的内存了。 STATIC INLINE VOID *OsMemAlloc(struct OsMemPoolHead *pool, UINT32 size, UINT32 intSave) {struct OsMemNodeHead *allocNode NULL;#if (LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK 1)if (OsMemAllocCheck(pool, intSave) LOS_NOK) {return NULL;} #endif⑴ UINT32 allocSize OS_MEM_ALIGN(size OS_MEM_NODE_HEAD_SIZE, OS_MEM_ALIGN_SIZE);#if OS_MEM_EXPAND_ENABLE retry: #endif ⑵ allocNode OsMemFreeNodeGet(pool, allocSize);if (allocNode NULL) { #if OS_MEM_EXPAND_ENABLEif (pool-info.attr OS_MEM_POOL_EXPAND_ENABLE) {INT32 ret OsMemPoolExpand(pool, allocSize, intSave);if (ret 0) {goto retry;}} #endifPRINT_ERR(-----------------------------------------------------------------------------------------------------------\n);MEM_UNLOCK(pool, intSave);OsMemInfoPrint(pool);MEM_LOCK(pool, intSave);PRINT_ERR([%s] No suitable free block, require free node size: 0x%x\n, __FUNCTION__, allocSize);PRINT_ERR(-----------------------------------------------------------------------------------------------------------\n);return NULL;}⑶ if ((allocSize OS_MEM_MIN_LEFT_SIZE) allocNode-sizeAndFlag) {OsMemSplitNode(pool, allocNode, allocSize);}⑷ OS_MEM_NODE_SET_USED_FLAG(allocNode-sizeAndFlag);OsMemWaterUsedRecord(pool, OS_MEM_NODE_GET_SIZE(allocNode-sizeAndFlag));#if (LOSCFG_MEM_LEAKCHECK 1)OsMemLinkRegisterRecord(allocNode); #endif ⑸ return OsMemCreateUsedNode((VOID *)allocNode); }2.4 按指定字节对齐申请动态内存 我们还可以使用函数VOID *LOS_MemAllocAlign(VOID *pool, UINT32 size, UINT32 boundary)从指定动态内存池中申请长度为size且地址按boundary字节对齐的内存。该函数需要3个参数VOID *pool为内存池起始地址UINT32 size为需要申请的内存大小UINT32 boundary内存对齐数值。当申请内存后得到的内存地址VOID *ptr对齐后的内存地址为VOID *alignedPtr二者的偏移值使用UINT32 gapSize保存。因为已经按OS_MEM_ALIGN_SIZE内存对齐了最大偏移值为boundary - OS_MEM_ALIGN_SIZE。下面分析下源码。 ⑴处对参数进行校验内存池地址不能为空申请的内存大小不能为0对齐字节boundary不能为0还需要是2的幂。申请的内存大小必须大于最小的申请值OS_MEM_MIN_ALLOC_SIZE。⑵处校验下对齐内存后是否会数据溢出。⑶处计算对齐后需要申请的内存大小然后判断内存大小数值没有已使用或已对齐标记。⑷处调用函数申请到内存VOID *ptr然后计算出对齐的内存地址VOID *alignedPtr如果二者相等则返回。⑸处计算出对齐内存的偏移值⑹处获取申请到的内存的头节点设置已对齐标记。⑺对偏移值设置对齐标记然后把偏移值保存在内存VOID *alignedPtr的前4个字节里。⑻处重新定向要返回的指针完成申请对齐的内存。 VOID *LOS_MemAllocAlign(VOID *pool, UINT32 size, UINT32 boundary) { #if OS_MEM_TRACEUINT64 start HalClockGetCycles(); #endifUINT32 gapSize;⑴ if ((pool NULL) || (size 0) || (boundary 0) || !OS_MEM_IS_POW_TWO(boundary) ||!OS_MEM_IS_ALIGNED(boundary, sizeof(VOID *))) {return NULL;}if (size OS_MEM_MIN_ALLOC_SIZE) {size OS_MEM_MIN_ALLOC_SIZE;}⑵ if ((boundary - sizeof(gapSize)) ((UINT32)(-1) - size)) {return NULL;}⑶ UINT32 useSize (size boundary) - sizeof(gapSize);if (OS_MEM_NODE_GET_USED_FLAG(useSize) || OS_MEM_NODE_GET_ALIGNED_FLAG(useSize)) {return NULL;}struct OsMemPoolHead *poolHead (struct OsMemPoolHead *)pool;UINT32 intSave;VOID *ptr NULL;VOID *alignedPtr NULL;MEM_LOCK(poolHead, intSave);do { ⑷ ptr OsMemAlloc(pool, useSize, intSave);alignedPtr (VOID *)OS_MEM_ALIGN(ptr, boundary);if (ptr alignedPtr) {break;}/* store gapSize in address (ptr - 4), it will be checked while free */ ⑸ gapSize (UINT32)((UINTPTR)alignedPtr - (UINTPTR)ptr); ⑹ struct OsMemUsedNodeHead *allocNode (struct OsMemUsedNodeHead *)ptr - 1;OS_MEM_NODE_SET_ALIGNED_FLAG(allocNode-header.sizeAndFlag); ⑺ OS_MEM_SET_GAPSIZE_ALIGNED_FLAG(gapSize);*(UINT32 *)((UINTPTR)alignedPtr - sizeof(gapSize)) gapSize; ⑻ ptr alignedPtr;} while (0);MEM_UNLOCK(poolHead, intSave);#if OS_MEM_TRACEUINT64 end HalClockGetCycles();UINT32 timeUsed MEM_TRACE_CYCLE_TO_US(end - start);LOS_Trace(LOS_TRACE_MEM_TIME, (UINTPTR)pool MEM_POOL_ADDR_MASK, MEM_TRACE_MEMALIGN, timeUsed); #endifOsHookCall(LOS_HOOK_TYPE_MEM_ALLOCALIGN, pool, size, boundary);return ptr; }2.5 释放动态内存 对申请的内存块使用完毕我们可以使用函数UINT32 LOS_MemFree(VOID *pool, VOID *ptr)来释放动态态内存需要2个参数VOID *pool是初始化过的动态内存池地址。VOID *ptr是需要释放的动态内存块的数据区的起始地址注意这个不是内存控制节点的地址。下面分析下源码⑴处对传入的参数先进行校验。⑵处获取校准内存对齐后的真实的内存地址然后获取内存节点头地址。⑶处调用函数OsMemFree(pool, ptr)完成内存的释放。 UINT32 LOS_MemFree(VOID *pool, VOID *ptr) { #if OS_MEM_TRACEUINT64 start HalClockGetCycles(); #endif⑴ if ((pool NULL) || (ptr NULL) || !OS_MEM_IS_ALIGNED(pool, sizeof(VOID *)) ||!OS_MEM_IS_ALIGNED(ptr, sizeof(VOID *))) {return LOS_NOK;}UINT32 ret LOS_NOK;struct OsMemPoolHead *poolHead (struct OsMemPoolHead *)pool;struct OsMemNodeHead *node NULL;UINT32 intSave;MEM_LOCK(poolHead, intSave);do { ⑵ ptr OsGetRealPtr(pool, ptr);if (ptr NULL) {break;}node (struct OsMemNodeHead *)((UINTPTR)ptr - OS_MEM_NODE_HEAD_SIZE); ⑶ ret OsMemFree(poolHead, node);} while (0);MEM_UNLOCK(poolHead, intSave);#if OS_MEM_TRACEUINT64 end HalClockGetCycles();UINT32 timeUsed MEM_TRACE_CYCLE_TO_US(end - start);LOS_Trace(LOS_TRACE_MEM_TIME, (UINTPTR)pool MEM_POOL_ADDR_MASK, MEM_TRACE_FREE, timeUsed); #endifOsHookCall(LOS_HOOK_TYPE_MEM_FREE, pool, ptr);return ret; }我们回过头来继续看下函数OsGetRealPtr()。⑴获取内存对齐的偏移值⑵如果偏移值同时标记为已使用和已对齐则返回错误。⑶如果偏移值标记为已对齐则执行⑷去除对齐标记获取不带标记的偏移值。然后执行⑸获取内存对齐之前的数据区内存地址。 STATIC INLINE VOID *OsGetRealPtr(const VOID *pool, VOID *ptr) {VOID *realPtr ptr; ⑴ UINT32 gapSize *((UINT32 *)((UINTPTR)ptr - sizeof(UINT32)));⑵ if (OS_MEM_GAPSIZE_CHECK(gapSize)) {PRINT_ERR([%s:%d]gapSize:0x%x error\n, __FUNCTION__, __LINE__, gapSize);return NULL;}⑶ if (OS_MEM_GET_GAPSIZE_ALIGNED_FLAG(gapSize)) { ⑷ gapSize OS_MEM_GET_ALIGNED_GAPSIZE(gapSize);if ((gapSize (OS_MEM_ALIGN_SIZE - 1)) ||(gapSize ((UINTPTR)ptr - OS_MEM_NODE_HEAD_SIZE - (UINTPTR)pool))) {PRINT_ERR([%s:%d]gapSize:0x%x error\n, __FUNCTION__, __LINE__, gapSize);return NULL;} ⑸ realPtr (VOID *)((UINTPTR)ptr - (UINTPTR)gapSize);}return realPtr; }2.6 重新申请动态内存 我们还可以使用函数VOID *LOS_MemRealloc(VOID *pool, VOID *ptr, UINT32 size)按指定size大小重新分配内存块并将原内存块内容拷贝到新内存块。如果新内存块申请成功则释放原内存块。该函数需要3个参数VOID *pool为内存池起始地址VOID *ptr为之前申请的内存地址UINT32 size为重新申请的内存大小。返回值为新内存块地址或者返回NULL。下面分析下源码。 ⑴处对参数进行校验内存池地址不能为空内存大小不能含有已使用、已对齐标记。⑵处如果传入的内存地址为空则等价于LOS_MemAlloc()函数。⑶如果传入size为0等价于函数LOS_MemFree()。⑷处保证申请的内存块大小至少为系统允许的最小值OS_MEM_MIN_ALLOC_SIZE。⑸处获取内存对齐之前的内存地址上文已分析该函数OsGetRealPtr()。⑹处由数据域内存地址计算出内存控制节点node的内存地址然后执行⑺处函数重新申请内存。 VOID *LOS_MemRealloc(VOID *pool, VOID *ptr, UINT32 size) { #if OS_MEM_TRACEUINT64 start HalClockGetCycles(); #endif⑴ if ((pool NULL) || OS_MEM_NODE_GET_USED_FLAG(size) || OS_MEM_NODE_GET_ALIGNED_FLAG(size)) {return NULL;}OsHookCall(LOS_HOOK_TYPE_MEM_REALLOC, pool, ptr, size);⑵ if (ptr NULL) {return LOS_MemAlloc(pool, size);}⑶ if (size 0) {(VOID)LOS_MemFree(pool, ptr);return NULL;}⑷ if (size OS_MEM_MIN_ALLOC_SIZE) {size OS_MEM_MIN_ALLOC_SIZE;}struct OsMemPoolHead *poolHead (struct OsMemPoolHead *)pool;struct OsMemNodeHead *node NULL;VOID *newPtr NULL;UINT32 intSave;MEM_LOCK(poolHead, intSave);do { ⑸ ptr OsGetRealPtr(pool, ptr);if (ptr NULL) {break;}⑹ node (struct OsMemNodeHead *)((UINTPTR)ptr - OS_MEM_NODE_HEAD_SIZE);if (OsMemCheckUsedNode(pool, node) ! LOS_OK) {break;}⑺ newPtr OsMemRealloc(pool, ptr, node, size, intSave);} while (0);MEM_UNLOCK(poolHead, intSave);#if OS_MEM_TRACEUINT64 end HalClockGetCycles();UINT32 timeUsed MEM_TRACE_CYCLE_TO_US(end - start);LOS_Trace(LOS_TRACE_MEM_TIME, (UINTPTR)pool MEM_POOL_ADDR_MASK, MEM_TRACE_REALLOC, timeUsed); #endifreturn newPtr; }继续分析下函数OsMemRealloc。⑴处处理重新申请的内存小于等于现有的内存的情况需要调用函数OsMemReAllocSmaller()进行分割分割完毕返回(VOID *)ptr即可。如果重新申请更大的内存则执行⑵处代码获取下一个节点然后执行⑶处理下一个节点可用且两个节点大小之和大于等于重新申请内存的大小allocSize。执行⑷处的函数合并节点重新分配内存。 如果连续的节点的大小不满足重新申请内存的大小则执行⑸处函数重新申请内存。申请成功后执行⑹把之前内存的数据复制到新申请的内存区域复制失败的话则把新申请的内存释放掉并返回NULL退出函数。如果复制成功继续执行⑺释放掉之前的节点。 STATIC INLINE VOID *OsMemRealloc(struct OsMemPoolHead *pool, const VOID *ptr,struct OsMemNodeHead *node, UINT32 size, UINT32 intSave) {struct OsMemNodeHead *nextNode NULL;UINT32 allocSize OS_MEM_ALIGN(size OS_MEM_NODE_HEAD_SIZE, OS_MEM_ALIGN_SIZE);UINT32 nodeSize OS_MEM_NODE_GET_SIZE(node-sizeAndFlag);VOID *tmpPtr NULL;⑴ if (nodeSize allocSize) {OsMemReAllocSmaller(pool, allocSize, node, nodeSize);return (VOID *)ptr;}⑵ nextNode OS_MEM_NEXT_NODE(node); ⑶ if (!OS_MEM_NODE_GET_USED_FLAG(nextNode-sizeAndFlag) ((nextNode-sizeAndFlag nodeSize) allocSize)) { ⑷ OsMemMergeNodeForReAllocBigger(pool, allocSize, node, nodeSize, nextNode);return (VOID *)ptr;}⑸ tmpPtr OsMemAlloc(pool, size, intSave);if (tmpPtr ! NULL) { ⑹ if (memcpy_s(tmpPtr, size, ptr, (nodeSize - OS_MEM_NODE_HEAD_SIZE)) ! EOK) {MEM_UNLOCK(pool, intSave);(VOID)LOS_MemFree((VOID *)pool, (VOID *)tmpPtr);MEM_LOCK(pool, intSave);return NULL;} ⑺ (VOID)OsMemFree(pool, node);}return tmpPtr; }小结 本文带领大家一起剖析了鸿蒙轻内核的静态内存模块的源代码包含动态内存的结构体、动态内存池初始化、动态内存申请、释放等。 如果大家想更加深入的学习 OpenHarmony 开发的内容不妨可以参考以下相关学习文档进行学习助你快速提升自己 OpenHarmony 开发环境搭建https://qr18.cn/CgxrRy 《OpenHarmony源码解析》https://qr18.cn/CgxrRy 搭建开发环境Windows 开发环境的搭建Ubuntu 开发环境搭建Linux 与 Windows 之间的文件共享…… 系统架构分析https://qr18.cn/CgxrRy 构建子系统启动流程子系统分布式任务调度子系统分布式通信子系统驱动子系统…… OpenHarmony 设备开发学习手册https://qr18.cn/CgxrRy OpenHarmony面试题内含参考答案https://qr18.cn/CgxrRy
http://www.hkea.cn/news/14313569/

相关文章:

  • wordpress 查询 插件seo sem 做网站
  • 郑州免费建站怎么用微信官方网站做二维码
  • 重庆哪个网站建设比较好响应式网站建设公司
  • 一朋友做网站网站被抓了h5游戏搭建
  • 集团网站建设方案书手机网站建设林肖
  • 简述网站建设在作用WordPress的FTP登录凭据
  • 网站网页设计html公司网站建设吧个好
  • 遵义做百度网站一年多少钱下列关于网站开发中网页上传
  • 柳州住房和城乡建设局网站深圳哪个区的房子最值得投资
  • 网站开发费用摊销年限免费的微网站制作
  • 求职网站的建设方案中国品牌网官网查询
  • 制作网站注册页面WordPress默认头像修改方法
  • 怎样把有用网站做图标放在桌面怎么做网站广告卖钱
  • 成都金铭 网站建设建设什么网站好
  • 潮汕学院网站开发高校校园网站建设项目的要求
  • 做彩妆网站的公司住房与城乡建设网上办事大厅
  • 山东省住房与建设厅网站首页个人简历制作
  • 建设厅网站怎么查询安全员c考试成绩seo的概念是什么
  • 昌吉州住房和城乡建设局网站系统做网站的地方
  • 做酷炫网站能卖钱吗烟台做网站的价格
  • 无锡网站建设系统宣汉网站建设
  • 网站小图标 免费wordpress网页图片加载很慢
  • 网站制作的预算除了91还有什么关键词
  • 有经验的永州网站建设最火的网络推广平台
  • 有专门教做家具的网站2022年中国企业500强名单
  • 本墨陈黑做网站有版权怎么自己做网站赚钱
  • 厦门专业建站系统制作公司南通哪里有做网站的
  • ppt模板下载的网站有哪些品牌软文案例
  • 大学生做爰网站长沙公司建设网站
  • 旅游做攻略的网站有哪些个人博客首页