Abstract: This paper leads us to analyze the hongmeng light kernel dynamic memory module source code, including dynamic memory structure, dynamic memory pool initialization, dynamic memory application, release, etc.
This article is shared by huawei cloud community “Hongmong light kernel M core source code analysis series nine Dynamic Memory part 1”, original author: zhushy.
The memory management module manages the memory resources of the system. As one of the core modules of the operating system, it mainly includes the initialization, allocation and release of the memory.
During the running of the system, the memory management module manages the usage of memory by users and OS through the application and release of memory, so as to optimize the utilization and efficiency of memory and solve the problem of memory fragmentation to the maximum extent.
Hongmeng light kernel memory management is divided into static memory management and dynamic memory management, providing memory initialization, allocation, release and other functions.
-
Dynamic memory: Allocates a block of memory of a specified size in the dynamic memory pool.
-
Advantage: according to need distribution.
-
Disadvantages: Fragmentation may occur in the memory pool.
-
Static memory: A block of memory of preset (fixed) size at user initialization is allocated to a static memory pool.
-
Advantages: Efficient allocation and release, and no fragmentation in the static memory pool.
-
Disadvantages: You can only apply for the preset size of the initial memory block, not on demand.
After looking at static memory in the last series, we started looking at dynamic memory. Dynamic memory management is mainly used in scenarios where users need to use memory blocks of varying sizes. When the user needs to use the memory, the dynamic memory application function of the operating system can obtain a specified size of the memory block. Once the memory is used, the dynamic memory release function can return the occupied memory, so that the memory can be reused.
Based on OpenHarmony LitEOS-M dynamic internal presence TLSF algorithm, interval partitioning is optimized to achieve better performance and reduce fragmentation rate. Dynamic memory core algorithm block diagram is as follows:
Multiple free linked lists are used for management based on the size of free memory blocks. According to the size of free memory blocks, it is divided into two parts: [4, 127] and [27, 231], as shown in the size class above:
- The memory in the interval [4,127] is divided equally, as shown in green in the figure above, into 31 cells. The size of each cell corresponds to a multiple of 4 bytes. Each cell corresponds to a free memory linked list and a bit used to mark whether the corresponding free memory linked list is empty. When the value is 1, the free list is not empty. The memory in the [4,127] range is marked with a 32-bit unsigned integer bitmap.
- Free memory blocks larger than 127 bytes are managed as free linked lists with a power of 2. It is divided into 24 cells in total, and each cell is equally divided into 8 second-level cells. See the blue Size Class and Size SubClass in the figure above. Each secondary cell corresponds to a free linked list and a bit used to mark whether the corresponding free memory linked list is empty. A total of 24*8=192 secondary cell Spaces, corresponding to 192 free linked lists and 192/32=6 32-bit unsigned integer bitmap tokens.
For example, when there are 40 bytes of free memory that need to be inserted into a free linked list, it corresponds to the cell [40,43], the 10th free linked list, and the 10th bit of the bitmap marker. Mount the 40 bytes of free memory on the 10th free linked list and determine if bitmap markers need to be updated. When 40 bytes of memory need to be applied, the free linked list of memory blocks that meet the required size can be obtained according to bitmap markers, and free memory nodes can be obtained from the free linked list. If the allocated nodes are larger than the required memory size, split the nodes and mount the remaining nodes to the corresponding free linked list. When 580 bytes of free memory need to be inserted into the free list, corresponding to the second cell [2^9,2^9+2^6], 31+2*8=47 free list, the second bitmap marker of the 17th bit. Mount 580 bytes of free memory on the 47th free linked list and determine if bitmap markers need to be updated. When 580 bytes of memory need to be applied for, the free linked list of memory blocks that meet the required size can be obtained according to bitmap markers, and free memory nodes can be obtained from the free linked list. If the allocated nodes are larger than the required memory size, split the nodes and mount the remaining nodes to the corresponding free linked list. If the corresponding free list is empty, a larger memory range is used to check whether there are free lists that meet the requirements. In actual calculation, the free list that meets the required size will be found at a time.
The dynamic memory management structure is shown below:
- Memory pool header
The memory pool header section contains the memory pool information and the bitmap tag array and the free linked list array. Memory pool information includes the start address of the memory pool, the total size of the heap area, and memory pool properties. The bitmap tag array consists of seven 32-bit unsigned integers, each bit marking whether the corresponding free linked list is mounted on a free memory block node. The free memory linked list contains 223 free memory head node information. Each free memory head node information maintains the memory nods and the precursor and successor free memory nodes in the free linked list.
- Memory pool node part
Contains three types of nodes: unused memory nodes, used memory nodes, and tail nodes. Each memory node maintains a preorder pointer to the last memory node in the memory pool, maintains the size and usage markers, and marks the size and usage of the memory node. Data fields behind free memory nodes and used memory nodes. Tail nodes have no data fields.
This paper analyzes the source code of dynamic memory module to help readers master the use of dynamic memory. The source code in this article, using the OpenHarmony LitEOS-M kernel as an example, is available on the open source site gitee.com/openharmony… To obtain. Next, we look at the structure of dynamic memory, dynamic memory initialization, dynamic memory common operations of the source code.
1. Dynamic memory structure definition and common macro definition
1.1 Dynamic memory structure definition
The structure of dynamic memory is OsMemPoolInfo, OsMemPoolHead, OsMemNodeHead. The structure of memory node is OsMemUsedNodeHead. Free memory node structure OsMemFreeNodeHead. These constructs are defined in the file kernel\ SRC \mm\los_memory.c. The member variables of each structure will be illustrated below in combination with the dynamic memory management structure diagram above.
1.1.1 Dynamic Memory Pool Header structure
The dynamic memory pool information structure OsMemPoolInfo maintains the starting address and size information of the memory pool. The three main members are the starting address of the memory pool pool size poolSize and the memory value attribute attr. If the macro LOSCFG_MEM_WATERLINE is enabled, the waterline value of the memory pool is also maintained.
struct OsMemPoolInfo { VOID *pool; /* Start MEMORY address of the memory pool */ UINT32 totalSize; /* Total memory pool size */ UINT32 ATTR; /* Memory pool attributes */ #if (LOSCFG_MEM_WATERLINE == 1) UINT32 waterLine; /* Maximum memory usage in the memory pool */ UINT32 curUsedSize; /* The current size of the memory pool */ #endif};Copy the code
Struct OsMemPoolInfo info, OsMemPoolHead, OsMemPoolHead, OsMemPoolInfo, OsMemPoolInfo One is the free memory linked list array freeList[]. Macro definitions OS_MEM_BITMAP_WORDS and OS_MEM_FREE_LIST_COUNT are described later.
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
};
Copy the code
1.1.2 Dynamic Memory Pool Architecture of memory nodes
If the memory node integrity check macro LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK is enabled, it will maintain the magic word. Magic for verification. (2) if the memory leak checking macro is enabled, the link register array linkReg[] is maintained. The member variable at (3) is a pointer assembly. Each memory section in the memory pool nods to maintain the pointer to execute the previous memory node. (4) Maintain the size and markup information of memory nodes.
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] #endif union { 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; #else UINT32 sizeAndFlag; #endif };Copy the code
Then look at the used memory node structure OsMemUsedNodeHead, which is relatively simple and directly uses the dynamic memory node nod structure OsMemNodeHead as the only member.
struct OsMemUsedNodeHead {
struct OsMemNodeHead header;
};
Copy the code
In addition to the OsMemNodeHead member, there are two Pointers to the last and next free memory nodes.
struct OsMemFreeNodeHead {
struct OsMemNodeHead header;
struct OsMemFreeNodeHead *prev;
struct OsMemFreeNodeHead *next;
};
Copy the code
1.2 Dynamic memory core algorithm related macros and functions
Dynamic memory also provides some TLSF algorithm related macro definitions and inline functions. These macros are very important and need to be familiar with these macro definitions before analyzing the source code. The dynamic memory core algorithm block diagram above can be used for learning. 2^n,2^(n+1)], where (n =7,8… 30) Large memory blocks in the interval are divided into 2^3=8 equally. The macro at (2) defines the small memory blocks in the interval of [4,127] divided into 31, namely, 4,8,12… , 124. (3) Define the upper bound value of small memory, considering memory alignment and granularity, the maximum value can only be set to 124.
(2^n,2^(n+1)), (n =7,8… 30) The partition is divided into 24 partitions, where n=7 is the OS_MEM_LARGE_START_BUCKET macro defined at ⑺. ⑻ the length of the linked list of free memory. The length of the bitmap array in the free linked list is the length of the bitmap array in the free linked list. The 31 small bits of memory use 1 bitmap word, so it needs to add 1. We will define bitmap masks where each bitmap word is a 32-bit unsigned integer.
Let’s move on to the inline function. (11) the function looks for the first bit of 1 in a bitmap word. This implementation works like the built-in __builtin_ctz function. This function is used to get the first free memory linked list containing the free memory block in the bitmap word corresponding to the free memory linked list. (12) takes the last 1 bit in the bitmap word, (the 32-bit binary values are 0,1,… from left to right. , 31). Log in the setting function is abbreviated to logarithm. The Log function is used to calculate the integer part of the logarithm base 2. (14) obtain the size level number of memory interval (14). For less than 128 bytes, there are 31 levels, and pairs are in [2^n,2^(n+1)], where (n =7,8,… 30) Range of memory, there are 24 levels. (15) is used to obtain the number between two level cells based on the size of memory, and the pair is in [2^n,2^(n+1)], where (n =7,8… 30) interval of memory, there are 8 secondary cells between.
/* The following is the macro definition and interface implementation related to the TLSF. */ /* Supposing a Second */ 1 #define OS_MEM_SLI 3 /* Giving 1 free list for each small bucket: 4, 8, 12, ⑶ #define OS_MEM_SMALL_BUCKET_MAX_SIZE 128 /* Giving 2^OS_MEM_SLI */ ⑷ #define OS_MEM_LARGE_BUCKET_COUNT 24 /* OS_MEM_SMALL_BUCKET_MAX_SIZE to the power */ ⑻ #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: */ ⑼ DEFINE OS_MEM_BITMAP_WORDS ((OS_MEM_FREE_LIST_COUNT >> 5) + 1) → → DEFINE OS_MEM_BITMAP_MASK 0x1FU /* Used */ 11 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. */ na-12 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 = (siSIZE - 2^f) * 2^SLI / 2^ F. */ participant 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)); }Copy the code
2. Common operations of dynamic memory
Dynamic memory management module provides users with initialization and delete memory pool, application, release dynamic memory and other operations, let’s analyze the source code of the interface. Before looking at memory manipulation interfaces, let’s take a look at common internal interfaces.
2.1 Dynamic Memory Internal Interfaces
2.1.1 Setting and clearing free memory linked list flag bits
OsMemSetFreeListBit (); OsMemSetFreeListBit (); OsMemSetFreeListBit (); OsMemSetFreeListBit (); OsMemSetFreeListBit (); When free memory blocks are attached to the free memory linked list, the bitmap word must be set to 1. The OsMemClearFreeListBit function at ⑴ does the opposite operation. When free memory blocks are no longer mounted on the free memory linked list, the corresponding bit should be cleared to zero.
STATIC INLINE VOID OsMemSetFreeListBit(struct OsMemPoolHead *head, UINT32 index) {(1) the head - > freeListBitmap [index > > 5) | = 1 u < < (index & 0 x1f); } STATIC INLINE VOID OsMemClearFreeListBit(struct OsMemPoolHead *head, UINT32 INDEX) {⑵ head->freeListBitmap[index >> 5] &= ~(1U << (index & 0x1F)); }Copy the code
2.1.2 Merging Memory Nodes
The VOID OsMemMergeNode(struct OsMemNodeHead *node) function is used to merge the given node struct OsMemNodeHead *node with its previous free node. At ⑴, add the size of the previous node to the size of the node to be joined. (2) obtain the next node of a given node, and then perform ⑶ to point its previous node to the previous node of a given node to complete the merging of nodes. The OS_MEM_NODE_GET_LAST_FLAG macro is used to determine whether the node is the last node. The default value is 0. You can view the macro definition.
STATIC INLINE VOID OsMemMergeNode(struct OsMemNodeHead *node) { struct OsMemNodeHead *nextNode = NULL; (1) 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; }}Copy the code
2.1.3 Splitting Memory Nodes
The VOID OsMemSplitNode(VOID *pool, struct OsMemNodeHead *allocNode, UINT32 allocSize) function is used to split memory nodes. It takes three parameters. VOID *pool is the start address of a memory pool, struct OsMemNodeHead *allocNode indicates the required memory allocated from the memory node, UINT32 allocSize indicates the required memory allocated. The remainder of the partition is merged if the next node is idle. The remaining partitioned nodes are mounted to the free memory linked list.
(1) newFreeNode is the allocated free memory node, set its last node to the allocated node, and set the size of the remaining memory. (2) adjust the size of the allocated memory, (3) fetch the next node, and (4) set the previous node of the next node to the newFreeNode newFreeNode. ⑸ check whether the next node is used. If not, delete the next node from the linked list, and then merge it with the idle node newFreeNode. ⑹ Mount the remaining free memory nodes to the linked list.
STATIC INLINE VOID OsMemSplitNode(VOID *pool, struct OsMemNodeHead *allocNode, UINT32 allocSize) { struct OsMemFreeNodeHead *newFreeNode = NULL; struct OsMemNodeHead *nextNode = NULL; ⑴ newFreeNode = (struct OsMemFreeNodeHead *)(VOID *)((UINT8 *) newFreeNode->header.ptr.prev = allocNode; newFreeNode->header.sizeAndFlag = allocNode->sizeAndFlag - allocSize; 2 allocNode - > sizeAndFlag = allocSize; (3) 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); }Copy the code
2.1.4 Applying for memory Again
The OsMemReAllocSmaller() function is used to re-allocate a smaller memory from a larger memory block. It takes the following 4 arguments: VOID * POOL is the start address of a memory pool, UINT32 allocSize is the size of reapplied memory, struct OsMemNodeHead *node is the memory node that needs to be reallocated, UINT32 nodeSize is the size of the node. ⑴ Set the memory node selfnode. sizeAndFlag as the actual size after removing the mark. ⑵ Split the node as required.
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} (3) OS_MEM_NODE_SET_USED_FLAG (node - > sizeAndFlag); #if (LOSCFG_MEM_LEAKCHECK == 1) OsMemLinkRegisterRecord(node); #endif }Copy the code
2.1.5 Merging nodes Apply for memory again
Finally, under the look at function OsMemMergeNodeForReAllocBigger (), is used to merge the memory node, redistribute more memory space. VOID *pool is the start address of the memory pool, UINT32 allocSize is the size of the reapplied memory, struct OsMemNodeHead *node is the memory node that needs to be reallocated. UINT32 nodeSize indicates the size of the current node, struct OsMemNodeHead *nextNode indicates the next memory node. (1) Set the size of the memory node to the actual size after removing the mark, (2) remove the next node from the list, and then merge the nodes. ⑶ if the size of the combined nodes exceeds the size that needs to be reallocated, the nodes are split. (4) Mark the applied memory node as used, and complete the memory application
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); } (4) OS_MEM_NODE_SET_USED_FLAG (node - > sizeAndFlag); OsMemWaterUsedRecord((struct OsMemPoolHead *)pool, node->sizeAndFlag - nodeSize); #if (LOSCFG_MEM_LEAKCHECK == 1) OsMemLinkRegisterRecord(node); #endif }Copy the code
2.1.6 Operations related to free Memory Linked Lists
Dynamic memory provides several operations on the free memory linked list. Let’s examine the code for these operations in turn. First look at the function OsMemFreeListIndexGet, which retrives the index of the free memory linked list based on the memory node size. (1) retrieves the primary index, (2) retrieves the secondary index, and then evaluates the index of the free list and returns it.
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); }Copy the code
Next, take a look at the function OsMemListAdd to insert the free memory node into the free memory linked list. (1) Get the first node of the free linked list. If the node is not empty, set the precursor node of this node as node to be inserted. (2) set the precursor and successor of the node to be inserted, and then assign this node to the free linked list Pool ->freeList[listIndex]. Finally, execute the ⑶ code, set the free list bitmap word, and set the magic word.
STATIC INLINE VOID OsMemListAdd(struct OsMemPoolHead *pool, UINT32 listIndex, Struct OsMemFreeNodeHead *node) {⑴ OsMemFreeNodeHead *node = pool->freeList[listIndex]; if (firstNode ! = NULL) { firstNode->prev = node; } ⑵ node->prev = NULL; node->next = firstNode; pool->freeList[listIndex] = node; (3) OsMemSetFreeListBit (pool, listIndex); OS_MEM_SET_MAGIC(&node->header); }Copy the code
Finally, we examine how the function OsMemListDelete removes the specified free memory node from the free memory linked list. If the node to be deleted is the first node in the free memory linked list, the free linked list needs to be executed to the next node of the node to be deleted. If the next node is empty, you need to perform (2) to clear the bitmap word of the free list. Otherwise, perform ⑶ to set the precursor node of the next node to null. If the node to be deleted is not the first node in the free list, perform ⑷ to set the successor node of the precursor node to be deleted as the successor node of the node to be deleted. If the node to be deleted is not the last node, perform ⑸ (5) to set the precursor node of the successor node to the precursor node of the node to be deleted. Finally, I need to set up the magic word.
STATIC INLINE VOID OsMemListDelete(struct OsMemPoolHead *pool, UINT32 listIndex, Struct OsMemFreeNodeHead *node) {⑴ if (node == pool->freeList[listIndex]) {pool-> listIndex = node->next; If (node->next == NULL) {⑵ OsMemClearFreeListBit(pool, listIndex); } else {⑶ node->next->prev = NULL; * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * if (node->next ! {⑸ node->next->prev = node->prev; } } OS_MEM_SET_MAGIC(&node->header); }Copy the code
2.1.7 Operations related to Free Memory Nodes
Dynamic memory provides several operations for free memory, such as OsMemFreeNodeAdd, OsMemFreeNodeDelete, and OsMemFreeNodeGet.
The OsMemFreeNodeAdd function is used to add a free memory node to the corresponding free memory linked list. (1) To get the index of the free memory linked list, and (2) to add the free memory node to the free list.
STATIC INLINE VOID OsMemFreeNodeAdd(VOID *pool, Struct OsMemFreeNodeHead *node) {⑴ 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); }Copy the code
The OsMemFreeNodeDelete function is used to remove a free memory node from the corresponding free memory linked list. The code is relatively simple, get the index of the free memory linked list, and then call the function OsMemListDelete to delete.
STATIC INLINE VOID OsMemFreeNodeDelete(VOID *pool, struct OsMemFreeNodeHead *node)
{
UINT32 index = OsMemFreeListIndexGet(node->header.sizeAndFlag);
OsMemListDelete(pool, index, node);
}
Copy the code
The OsMemFreeNodeGet function obtains free memory blocks that meet the size criteria based on the memory pool address and required memory size. (1) call the function to obtain the memory block that meets the size condition, and then execute (2) to delete the obtained memory block from the free memory linked list and return the memory node address.
STATIC INLINE struct OsMemNodeHead *OsMemFreeNodeGet(VOID *pool, UINT32 size) { struct OsMemPoolHead *poolHead = (struct OsMemPoolHead *)pool; UINT32 index; (1) struct OsMemFreeNodeHead * firstNode = OsMemFindNextSuitableBlock (pool, the size, & index); if (firstNode == NULL) { return NULL; } ⑵ OsMemListDelete(poolHead, index, firstNode); return &firstNode->header; }Copy the code
Finally, analysis the function OsMemFindNextSuitableBlock. (1) Obtain the number of the first-level interval according to the size of the required memory block. If the applied memory is in the range [4,127], perform (2) to record the linked list index of free memory. If large memory is required, execute the code at step 3. First get the secondary interval index, and then calculate the index value index of the free memory linked list. (4) OsMemNotEmptyIndexGet (*); (4) OsMemNotEmptyIndexGet (*); Return the free linked list index value if a block of free memory is successfully obtained, otherwise proceed with the subsequent code. ⑹ traverses the bitmap word of the idle linked list, and the self-increasing variable index in the loop corresponds to the number of the first-level interval. If the bitmap word is not empty, perform ⑺ to obtain the largest index of the linked list of free memory that corresponds to the bitmap word.
If the operation reaches the ⑻ point, no suitable memory block is matched and a null pointer is returned. ‘levies department said there meet the free memory size list, call a function OsMemFindCurSuitableBlock the proper memory block and return. → we will tag the appropriate free memory linked list index and return the free memory linked list.
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 (os_small_bucket_count) {⑵ index = 1; } 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; } ⑼ outline = outline; return OsMemFindCurSuitableBlock(poolHead, curIndex, size); DONE: *outIndex = index; ⑽ return poolHead - > freeList [index]; }Copy the code
Let’s analyze the OsMemNotEmptyIndexGet function in detail. In (1), bitmap words are obtained according to the free memory linked list index. In (2), it is determined whether there are free memory blocks in the small second-level memory interval corresponding to the first-level memory interval corresponding to the free memory linked list index. If the value of index & OS_MEM_BITMAP_MASK is 5 bits lower than that of the index, the index value can be associated with the bitbit in the bitmap word. For example, if index is 39, the value of index & OS_MEM_BITMAP_MASK is 7, which corresponds to the seventh bitmap bit. The expression ~((1 << (index & OS_MEM_BITMAP_MASK)) -1) is used to represent the bitmap word corresponding to the index greater than the index of the free memory linked list. After the statement at ⑵ is executed, mask represents the value of the bitmap word corresponding to the list index whose free index value is greater than index. When mask is not 0, it means that there is a free memory block that meets the size of memory. Then, the code at the third part is executed, where OsMemFFS(mask) obtains the first bit of bitmap word that is 1, which corresponds to the linked list of mounted free memory blocks. (index & ~OS_MEM_BITMAP_MASK) corresponds to the high level of the linked list index. Add bitmap words to calculate the index value of the linked list with free memory that meets the application conditions.
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; }Copy the code
Finally, look at the function OsMemFindCurSuitableBlock again. (1) loops through the memory blocks mounted on the free memory linked list. If the size of the memory blocks traversed is larger than the required size, perform (2) to return the free memory blocks. Otherwise a null pointer is returned.
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; }Copy the code
2.2 Initializing a Dynamic Memory Pool
We analyze the code for initializing the dynamic memory pool function UINT32 LOS_MemInit(VOID *pool, UINT32 size). VOID *pool indicates the start address of the dynamic memory pool. UINT32 SIZE indicates the total size of the initialized dynamic memory pool. Size must be smaller than or equal to the size of the memory area at the beginning of the pool. OS_MEM_MIN_POOL_SIZE is also required to be greater than the minimum value of the dynamic memory pool. [pool, pool + size] Cannot conflict with other memory pools.
(1) validates the passed parameter, (2) validates the passed parameter for memory alignment, and returns an error code if there is no memory alignment. (3) The OsMemPoolInit() function is called to initialize the memory pool, which is the core function for initializing memory. * * * * * * * * * * * * * * * * * * * * * * * * * * * *
UINT32 LOS_MemInit(VOID *pool, UINT32 size) {(1) if ((pool = = NULL) | | (size < = OS_MEM_MIN_POOL_SIZE)) {return OS_ERROR; } [2] the 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 (OsMemPoolAdd(pool, size)) {(VOID)OsMemPoolDeinit(pool); return OS_ERROR; } #endif #if OS_MEM_TRACE LOS_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); #endif OsHookCall(LOS_HOOK_TYPE_MEM_INIT, pool, size); return LOS_OK; }Copy the code
Let’s move on to the function OsMemPoolInit(). (1) struct OsMemPoolHead * start address and size of poolHead; (2) set the attributes of the pool to locked and unextensible. Fetch the first memory control node of the memory pool and set its size equal to the total size of the memory pool minus the size of the head of the memory pool and the size of the head of one memory section. OS_MEM_END_NODE(pool, size) Specifies the last node in the memory pool.
(4) the macro is called to set the magic word for the node, and then the memory node is inserted into the free memory linked list. ⑸ get the tail node of the memory pool, set the magic word, and then execute ⑹ set the tail node size to 0 and set the last node, and set the used mark. If the debug macro LOSCFG_MEM_WATERLINE is enabled, there are some other operations, which can be read by yourself.
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)); (1) 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); (4) 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_ENABLE endNode->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; #endif return LOS_OK; }Copy the code
2.3 Applying for Dynamic Memory
After initializing the dynamic memory pool, we can use the VOID *LOS_MemAlloc(VOID *pool, UINT32 size) function to apply for dynamic memory.
(1) Verify the parameters. The address of the memory pool cannot be empty, and the size of the applied memory cannot be 0. (2) determine whether the requested memory size is marked as used or memory aligned. OsMemAlloc(poolHead, size, intSave);
VOID *LOS_MemAlloc(VOID *pool, UINT32 size) { #if OS_MEM_TRACE UINT64 start = HalClockGetCycles(); # endif (1) 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 {2 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_TRACE UINT64 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); #endif OsHookCall(LOS_HOOK_TYPE_MEM_ALLOC, pool, size); return ptr; }Copy the code
We continue to analyze the function OsMemAlloc(). (2) Obtain a free memory block that meets the required size from the free memory linked list. If the application fails, an error message will be printed. (3) If the memory block found is larger than the required size, the partition operation is performed. (4) The allocated memory nodes are marked as used, and the waterline records are updated. ⑸ returns the address of the data area of the memory block. This is achieved by adding 1 to the memory node address to locate the memory address of the data area. The requested memory is ready to be used in the function that calls the requested memory.
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_ENABLE if (pool->info.attr & OS_MEM_POOL_EXPAND_ENABLE) { INT32 ret = OsMemPoolExpand(pool, allocSize, intSave); if (ret == 0) { goto retry; } } #endif PRINT_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); } (4) 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); }Copy the code
2.4 Applying for dynamic memory based on specified byte alignment
We can also use the VOID *LOS_MemAllocAlign(VOID *pool, UINT32 SIZE, UINT32 boundary) function to apply for size memory with boundary byte aligned address from the specified dynamic memory pool. The function requires three parameters. VOID * POOL indicates the start address of the memory pool, UINT32 SIZE indicates the required memory size, UINT32 Boundary Indicates the value of memory alignment. The offset values of VOID *alignedPtr and VOID * PTR are saved using UINT32 gapSize. The maximum offset is boundary-OS_MEM_ALIGN_size because the memory has been aligned according to OS_MEM_ALIGN_SIZE. The following analysis of the source code.
(1) Check the parameters. The memory pool address cannot be empty, the applied memory size cannot be 0, and the aligned byte boundary cannot be 0. It also needs to be a power of 2. The required memory size must be greater than the minimum value OS_MEM_MIN_ALLOC_SIZE. (2) check whether data overflow occurs after memory alignment. (3) Calculate the memory size required after alignment, and then determine that there is no used or aligned memory size value. VOID *alignedPtr: VOID *alignedPtr: VOID *alignedPtr: VOID *alignedPtr ⑸ calculate the offset value of the aligned memory, ⑹ obtain the head node of the applied memory, set the aligned mark. ⑺ sets the alignment mark for the offset value, and stores the offset value in the first 4 bytes of memory VOID *alignedPtr. ⑻ redirect the pointer to return to complete the application for aligned memory.
VOID *LOS_MemAllocAlign(VOID *pool, UINT32 size, UINT32 boundary) { #if OS_MEM_TRACE UINT64 start = HalClockGetCycles(); #endif UINT32 gapSize; (1) 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 free */ ⑸ gapSize = (UINT32)(UINTPTR)alignedPtr - (UINTPTR) PTR); Struct OsMemUsedNodeHead *allocNode = (struct OsMemUsedNodeHead *) ptr-1; OS_MEM_NODE_SET_ALIGNED_FLAG(allocNode->header.sizeAndFlag); Once OS_MEM_SET_GAPSIZE_ALIGNED_FLAG (gapSize); *(UINT32 *)((UINTPTR)alignedPtr - sizeof(gapSize)) = gapSize; Being PTR = alignedPtr; } while (0); MEM_UNLOCK(poolHead, intSave); #if OS_MEM_TRACE UINT64 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); #endif OsHookCall(LOS_HOOK_TYPE_MEM_ALLOCALIGN, pool, size, boundary); return ptr; }Copy the code
2.5 Releasing Dynamic Memory
When the applied memory block is used, the function UINT32 LOS_MemFree(VOID *pool, VOID * PTR) is used to release the dynamic memory. VOID *pool is the initialized address of the dynamic memory pool. VOID * PTR is the starting address of the data area of the dynamic memory block to be freed. Note that this is not the address of the memory control node. The following analysis of the source code, the first to verify the incoming parameters. (2) get the actual memory address after calibrated memory alignment, and then get the memory section nod address. OsMemFree(pool, PTR);
UINT32 LOS_MemFree(VOID *pool, VOID *ptr) { #if OS_MEM_TRACE UINT64 start = HalClockGetCycles(); # endif (1) 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_TRACE UINT64 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); #endif OsHookCall(LOS_HOOK_TYPE_MEM_FREE, pool, ptr); return ret; }Copy the code
Let’s go back and look at the function OsGetRealPtr(). ⑴ gets the offset of memory alignment. ⑵ Returns an error if the offset is marked as both used and aligned. ⑶ If the offset value is marked as aligned, execute (4) to remove the alignment mark and obtain the unmarked offset value. Then execute ⑸ to obtain the memory address of the data area before memory alignment.
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); ⑵ 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)) {⑷ 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; } ⑸ VOID *)((UINTPTR) PTR - (UINTPTR)gapSize); } return realPtr; }Copy the code
2.6 Applying for Dynamic Memory Again
You can also use the VOID *LOS_MemRealloc(VOID *pool, VOID * PTR, UINT32 SIZE) function to reallocate memory blocks based on the specified size and copy the contents of the original memory block to the new memory block. If the new memory block is successfully applied for, the original memory block is released. The function requires three parameters. VOID *pool indicates the start address of a memory pool, VOID * PTR indicates the previously applied memory address, and UINT32 SIZE indicates the newly applied memory size. The return value is the address of the new memory block, or NULL. The following analysis of the source code.
(1) Verify the parameters. The memory pool address cannot be empty, and the memory size cannot contain used and aligned marks. If the memory address passed at ⑵ is empty, then this is equivalent to the LOS_MemAlloc() function. (3) If size is passed in 0, it is equivalent to LOS_MemFree(). * * * OS_MEM_MIN_ALLOC_SIZE specifies the minimum memory block size. OsGetRealPtr() = OsGetRealPtr(); ⑹ Calculate the memory address of the node based on the memory address of the data domain. Then run the ⑺ function to apply for memory again.
VOID *LOS_MemRealloc(VOID *pool, VOID *ptr, UINT32 size) { #if OS_MEM_TRACE UINT64 start = HalClockGetCycles(); # endif (1) 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 (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_TRACE UINT64 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); #endif return newPtr; }Copy the code
Moving on to the OsMemRealloc function. (1) : VOID * PTR; (2) : VOID * PTR; (3) : VOID * PTR; (4) : VOID * PTR; If you re-apply for a larger memory, the code (2) is executed to get the next node, and then the code (3) is executed to process the next node available and the sum of the two nodes is greater than or equal to the size of the re-applied memory allocSize. Execute the function at ⑷ to merge the nodes and reallocate memory.
If the size of the contiguous nodes does not meet the requirement of reapplying for memory, execute the function at ⑸ to reapply for memory. After the application succeeds, execute ⑹ copying the data of the previous memory to the newly applied memory area. If the replication fails, the newly applied memory is released and NULL is returned to exit the function. If the replication is successful, perform the ⑺ command to release the previous node.
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;
}
Copy the code
summary
This article led us to analyze the hongmeng light kernel dynamic memory module source code, including dynamic memory structure, dynamic memory pool initialization, dynamic memory application, release, etc. Thanks for reading. If you have any questions or suggestions, please leave a comment at gitee.com/openharmony… . To make it easier to find the light kernel repository, visit gitee.com/openharmony… “, follow Watch, like Star, and Fork to your account, thank you.
Click to follow, the first time to learn about Huawei cloud fresh technology ~