Memory Leak Check
Basic Concepts
As an optional function of the kernel, memory leak check is used to locate dynamic memory leak problems. After this function is enabled, the dynamic memory mechanism automatically records the link registers (LRs) used when memory is allocated. If a memory leak occurs, the recorded information helps locate the memory allocated for further analysis.
Function Configuration
LOSCFG_MEM_LEAKCHECK specifies the setting of the memory leak check. This function is disabled by default. You can enable it in Debug-> Enable MEM Debug-> Enable Function call stack of Mem operation recorded.
LOS_RECORD_LR_CNT specifies the number of LRs recorded. The default value is 3. Each LR consumes the memory of *sizeof(void ) bytes.
LOS_OMIT_LR_CNT specifies the number of ignored LRs. The default value is 2, which indicates that LRs are recorded from the time when LOS_MemAlloc is called. You can change the value based on actual requirements. The reasons for this configuration are as follows:
- LOS_MemAlloc is also called internally.
- LOS_MemAlloc may be encapsulated externally.
- The number of LRs configured by LOS_RECORD_LR_CNT is limited.
Correctly setting this macro can ignore invalid LRs and reduce memory consumption.
Development Guidelines
How to Develop
Memory leak check provides a method to check for memory leak in key code logic. If this function is enabled, LR information is recorded each time when memory is allocated. When LOS_MemUsedNodeShow is called before and after the code snippet is checked, information about all nodes that have been used in the specified memory pool is printed. You can compare the node information. The newly added node information indicates the node where the memory leak may occur. You can locate the code based on the LR and further check whether a memory leak occurs.
The node information output by calling LOS_MemUsedNodeShow is in the following format:
Each line contains information about a node. The first column indicates the node address, based on which you can obtain complete node information using a tool such as a GNU Debugger (GDB). The second column indicates the node size, which is equal to the node header size plus the data field size. Columns 3 to 5 list the LR addresses. You can determine the specific memory location of the node based on the LR addresses and the assembly file.
node size LR[0] LR[1] LR[2]
0x10017320: 0x528 0x9b004eba 0x9b004f60 0x9b005002
0x10017848: 0xe0 0x9b02c24e 0x9b02c246 0x9b008ef0
0x10017928: 0x50 0x9b008ed0 0x9b068902 0x9b0687c4
0x10017978: 0x24 0x9b008ed0 0x9b068924 0x9b0687c4
0x1001799c: 0x30 0x9b02c24e 0x9b02c246 0x9b008ef0
0x100179cc: 0x5c 0x9b02c24e 0x9b02c246 0x9b008ef0
CAUTION Enabling memory leak check affects memory application performance. LR addresses will be recorded for each memory node, increasing memory overhead.
Development Example
This example implements the following:
-
Call OsMemUsedNodeShow to print information about all nodes.
-
Simulate a memory leak by requesting memory without releasing it.
-
Call OsMemUsedNodeShow to print information about all nodes.
-
Compare the logs to obtain information about the node where a memory leak occurred.
-
Locate the code based on the LR address.
Sample Code
You can compile and verify the sample code in kernel/liteos_a/testsuites/kernel/src/osTest.c. The MemLeakTest() function is called in TestTaskEntry.
In this example, a memory pool is created. To achieve this purpose, you need to define LOSCFG_MEM_MUL_POOL in target_config.h.
The sample code is as follows:
#include <stdio.h>
#include <string.h>
#include "los_memory.h"
#include "los_config.h"
#define TEST_NEW_POOL_SIZE 2000
#define TEST_MALLOC_SIZE 8
void MemLeakTest(void)
{
VOID *pool = NULL;
/* Create a memory pool. */
pool = LOS_MemAlloc(OS_SYS_MEM_ADDR, TEST_NEW_POOL_SIZE);
(VOID)LOS_MemInit(pool, TEST_NEW_POOL_SIZE);
OsMemUsedNodeShow(pool);
void *ptr1 = LOS_MemAlloc(pool, TEST_MALLOC_SIZE);
void *ptr2 = LOS_MemAlloc(pool, TEST_MALLOC_SIZE);
OsMemUsedNodeShow(pool);
/* Release the memory pool. */
(VOID)LOS_MemDeInit(pool);
}
Verification
The log is as follows:
/* Log for the first OsMemUsedNodeShow. Because the memory pool is not allocated, there is no memory node. */
node LR[0] LR[1] LR[2]
/* Log for the second OsMemUsedNodeShow. There are two memory nodes. */
node LR[0] LR[1] LR[2]
0x00402e0d90: 0x004009f040 0x0040037614 0x0040005480
0x00402e0db0: 0x004009f04c 0x0040037614 0x0040005480
The difference between the two logs is as follows. The following memory nodes are suspected to have blocks with a memory leak.
0x00402e0d90: 0x004009f040 0x0040037614 0x0040005480
0x00402e0db0: 0x004009f04c 0x0040037614 0x0040005480
The following is part of the assembly file:
4009f014: 7d 1e a0 e3 mov r1, #2000
4009f018: 00 00 90 e5 ldr r0, [r0]
4009f01c: 67 7a fe eb bl #-398948 <LOS_MemAlloc>
4009f020: 7d 1e a0 e3 mov r1, #2000
4009f024: 00 40 a0 e1 mov r4, r0
4009f028: c7 79 fe eb bl #-399588 <LOS_MemInit>
4009f02c: 04 00 a0 e1 mov r0, r4
4009f030: 43 78 fe eb bl #-401140 <OsMemUsedNodeShow>
4009f034: 04 00 a0 e1 mov r0, r4
4009f038: 08 10 a0 e3 mov r1, #8
4009f03c: 5f 7a fe eb bl #-398980 <LOS_MemAlloc>
4009f040: 04 00 a0 e1 mov r0, r4
4009f044: 08 10 a0 e3 mov r1, #8
4009f048: 5c 7a fe eb bl #-398992 <LOS_MemAlloc>
4009f04c: 04 00 a0 e1 mov r0, r4
4009f050: 3b 78 fe eb bl #-401172 <OsMemUsedNodeShow>
4009f054: 3c 00 9f e5 ldr r0, [pc, #60]
4009f058: 40 b8 fe eb bl #-335616 <dprintf>
4009f05c: 04 00 a0 e1 mov r0, r4
4009f060: 2c 7a fe eb bl #-399184 <LOS_MemDeInit>
The memory node addressed by 0x4009f040 is not released after being allocated in MemLeakTest.