1# Memory Debugging 2 3 4The purpose of memory debugging is to locate problems related to dynamic memory. The kernel provides a variety of memory debugging methods. Dynamic memory pool statistics helps you learn the memory pool waterline and fragmentation rate. Memory leak check helps you accurately locate the code where memory leak occurs and analyze the memory usage of each module. Memory corruption check helps you locate memory corruptions. 5 6 7## Memory Information Statistics 8 9 10### Basic Concepts 11 12Memory information includes the memory pool size, memory usage, remaining memory size, maximum free memory, memory waterline, number of memory nodes, and fragmentation rate. 13 14- Memory waterline indicates the maximum memory used in a memory pool. The waterline value is updated upon each memory allocation and release. The memory pool size can be optimized based on this value. 15 16- Fragmentation rate indicates the fragmentation degree of the memory pool. If the fragmentation rate is high, there are a large number of free memory blocks in the memory pool but each block is small. You can use the following formula to calculate the fragmentation rate:<br>Fragmentation rate = 100 – 100 x Maximum free memory block size/Remaining memory size 17 18- You can use [APIs for memory management](kernel-mini-basic-memory.md) to scan node information in the memory pool and collect statistics. 19 20 21### Function Configuration 22 23**LOSCFG_MEM_WATERLINE** specifies the setting of the memory information statistics function. This function is enabled by default. To disable the function, set this macro to **0** in **target_config.h**. If you want to obtain the memory waterline, you must enable this macro. 24 25 26### Development Guidelines 27 28 29#### How to Develop 30 31Key structure: 32 33 34``` 35typedef struct { 36 UINT32 totalUsedSize; // Memory usage of the memory pool. 37 UINT32 totalFreeSize; // Remaining size of the memory pool. 38 UINT32 maxFreeNodeSize; // Maximum size of the free memory block in the memory pool. 39 UINT32 usedNodeNum; // Number of non-free memory blocks in the memory pool. 40 UINT32 freeNodeNum; // Number of free memory blocks in the memory pool. 41#if (LOSCFG_MEM_WATERLINE == 1) // The function is enabled by default. To disable it, set this macro to 0 in target_config.h. 42 UINT32 usageWaterLine; // Waterline of the memory pool. 43#endif 44} LOS_MEM_POOL_STATUS; 45``` 46 47To obtain the memory waterline, call **LOS_MemInfoGet**. The first parameter in the API is the start address of the memory pool, and the second parameter is the handle of the **LOS_MEM_POOL_STATUS** type. The **usageWaterLine** field indicates the waterline. 48 49To calculate the memory fragmentation rate, call **LOS_MemInfoGet** to obtain the remaining memory size and the maximum free memory block size in the memory pool, and then calculate the fragmentation rate of the dynamic memory pool as follows:<br>Fragmentation rate = 100 – 100 x Maximum free memory block size/Remaining memory size 50 51 52#### Development Example 53 54This example implements the following: 55 561. Create a monitoring task to obtain information about the memory pool. 57 582. Calls **LOS_MemInfoGet** to obtain the basic information about the memory pool. 59 603. Calculate the memory usage and fragmentation rate. 61 62 63#### Sample Code 64 65The sample code is as follows: 66 67The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **MemTest** function is called in **TestTaskEntry**. 68 69``` 70#include <stdio.h> 71#include <string.h> 72#include "los_task.h" 73#include "los_memory.h" 74#include "los_config.h" 75 76#define TEST_TASK_PRIO 5 77void MemInfoTaskFunc(void) 78{ 79 LOS_MEM_POOL_STATUS poolStatus = {0}; 80 81 /* pool is the memory address of the information to be collected. OS_SYS_MEM_ADDR is used as an example. */ 82 void *pool = OS_SYS_MEM_ADDR; 83 LOS_MemInfoGet(pool, &poolStatus); 84 /* Calculate the fragmentation rate of the memory pool. */ 85 float fragment = 100 - poolStatus.maxFreeNodeSize * 100.0 / poolStatus.totalFreeSize; 86 /* Calculate the memory usage of the memory pool. */ 87 float usage = LOS_MemTotalUsedGet(pool) * 100.0 / LOS_MemPoolSizeGet(pool); 88 printf("usage = %f, fragment = %f, maxFreeSize = %d, totalFreeSize = %d, waterLine = %d\n", usage, fragment, 89 poolStatus.maxFreeNodeSize, poolStatus.totalFreeSize, poolStatus.usageWaterLine); 90} 91 92int MemTest(void) 93{ 94 unsigned int ret; 95 unsigned int taskID; 96 TSK_INIT_PARAM_S taskStatus = {0}; 97 taskStatus.pfnTaskEntry = (TSK_ENTRY_FUNC)MemInfoTaskFunc; 98 taskStatus.uwStackSize = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE; 99 taskStatus.pcName = "memInfo"; 100 taskStatus.usTaskPrio = TEST_TASK_PRIO; 101 ret = LOS_TaskCreate(&taskID, &taskStatus); 102 if (ret != LOS_OK) { 103 printf("task create failed\n"); 104 return -1; 105 } 106 return 0; 107} 108``` 109 110 111#### Verification 112 113The result is as follows: 114 115 116``` 117usage = 0.458344, fragment = 0.000000, maxFreeSize = 16474928, totalFreeSize = 16474928, waterLine = 76816 118 119The preceding data may vary depending on the running environment. 120``` 121## Memory Leak Check 122 123 124### Basic Concepts 125 126As 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 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. 127 128 129### Function Configuration 130 131**LOSCFG_MEM_LEAKCHECK** specifies the setting of the memory leak check. This function is disabled by default. To enable the function, set this macro to **1** in **target_config.h**. 132 133**LOSCFG_MEM_RECORD_LR_CNT** specifies the number of LRs recorded. The default value is **3**. Each LR consumes the memory of **sizeof(void \*)** bytes. 134 135**LOSCFG_MEM_OMIT_LR_CNT** specifies the number of ignored LRs. The default value is **4**, which indicates that LRs are recorded from the time when **LOS_MemAlloc** is called. You can change the value based on actual requirements. This macro is configured because: 136 137- **LOS_MemAlloc** is also called internally. 138- **LOS_MemAlloc** may be encapsulated externally. 139- The number of LRs configured by **LOSCFG_MEM_RECORD_LR_CNT** is limited. 140 141Correctly setting this macro can ignore invalid LRs and reduce memory consumption. 142 143 144### Development Guidelines 145 146 147#### How to Develop 148 149Memory 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. 150 151The node information output by calling **LOS_MemUsedNodeShow** is in the following format: <br>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. 152 153 154``` 155node size LR[0] LR[1] LR[2] 1560x10017320: 0x528 0x9b004eba 0x9b004f60 0x9b005002 1570x10017848: 0xe0 0x9b02c24e 0x9b02c246 0x9b008ef0 1580x10017928: 0x50 0x9b008ed0 0x9b068902 0x9b0687c4 1590x10017978: 0x24 0x9b008ed0 0x9b068924 0x9b0687c4 1600x1001799c: 0x30 0x9b02c24e 0x9b02c246 0x9b008ef0 1610x100179cc: 0x5c 0x9b02c24e 0x9b02c246 0x9b008ef0 162``` 163 164> **CAUTION** 165> 166> Enabling memory leak check affects memory application performance. LR addresses will be recorded for each memory node, increasing memory overhead. 167 168 169#### Development Example 170 171This example implements the following: 172 1731. Call **LOS_MemUsedNodeShow** to print information about all nodes. 174 1752. Simulate a memory leak by requesting memory without releasing it. 176 1773. Call **LOS_MemUsedNodeShow** to print information about all nodes. 178 1794. Compare the logs to obtain information about the node where a memory leak occurred. 180 1815. Locate the code based on the LR address. 182 183 184#### Sample Code 185 186The sample code is as follows: 187 188The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **MemLeakTest** function is called in **TestTaskEntry**. 189 190When QEMU is running, ensure that the value of **LOSCFG_MEM_FREE_BY_TASKID** in **target_config.h** is **0**. 191 192After the memory check function is enabled, other tasks running on certain platforms may frequently print memory-related information such as "psp, start = xxxxx, end = xxxxxxx". Ignore the information or delete the print information called by **OsStackAddrGet**. 193 194 195``` 196#include <stdio.h> 197#include <string.h> 198#include "los_memory.h" 199#include "los_config.h" 200 201void MemLeakTest(void) 202{ 203 LOS_MemUsedNodeShow(LOSCFG_SYS_HEAP_ADDR); 204 void *ptr1 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8); 205 void *ptr2 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8); 206 LOS_MemUsedNodeShow(LOSCFG_SYS_HEAP_ADDR); 207} 208``` 209 210 211#### Verification 212 213The log is as follows: 214 215 216``` 217node size LR[0] LR[1] LR[2] 2180x20001b04: 0x24 0x08001a10 0x080035ce 0x080028fc 2190x20002058: 0x40 0x08002fe8 0x08003626 0x080028fc 2200x200022ac: 0x40 0x08000e0c 0x08000e56 0x0800359e 2210x20002594: 0x120 0x08000e0c 0x08000e56 0x08000c8a 2220x20002aac: 0x56 0x08000e0c 0x08000e56 0x08004220 223 224node size LR[0] LR[1] LR[2] 2250x20001b04: 0x24 0x08001a10 0x080035ce 0x080028fc 2260x20002058: 0x40 0x08002fe8 0x08003626 0x080028fc 2270x200022ac: 0x40 0x08000e0c 0x08000e56 0x0800359e 2280x20002594: 0x120 0x08000e0c 0x08000e56 0x08000c8a 2290x20002aac: 0x56 0x08000e0c 0x08000e56 0x08004220 2300x20003ac4: 0x1d 0x08001458 0x080014e0 0x080041e6 2310x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000 232 233The preceding data may vary depending on the running environment. 234``` 235 236The difference between the two logs is as follows. The following memory nodes are suspected to have blocks with a memory leak. 237 238 239``` 2400x20003ac4: 0x1d 0x08001458 0x080014e0 0x080041e6 2410x20003ae0: 0x1d 0x080041ee 0x08000cc2 0x00000000 242 243The preceding data may vary depending on the running environment. 244``` 245 246The following is part of the assembly file: 247 248 249``` 250 MemLeakTest: 251 0x80041d4: 0xb510 PUSH {R4, LR} 252 0x80041d6: 0x4ca8 LDR.N R4, [PC, #0x2a0] ; g_memStart 253 0x80041d8: 0x0020 MOVS R0, R4 254 0x80041da: 0xf7fd 0xf93e BL LOS_MemUsedNodeShow ; 0x800145a 255 0x80041de: 0x2108 MOVS R1, #8 256 0x80041e0: 0x0020 MOVS R0, R4 257 0x80041e2: 0xf7fd 0xfbd9 BL LOS_MemAlloc ; 0x8001998 258 0x80041e6: 0x2108 MOVS R1, #8 259 0x80041e8: 0x0020 MOVS R0, R4 260 0x80041ea: 0xf7fd 0xfbd5 BL LOS_MemAlloc ; 0x8001998 261 0x80041ee: 0x0020 MOVS R0, R4 262 0x80041f0: 0xf7fd 0xf933 BL LOS_MemUsedNodeShow ; 0x800145a 263 0x80041f4: 0xbd10 POP {R4, PC} 264 0x80041f6: 0x0000 MOVS R0, R0 265 266 The preceding data may vary depending on the running environment. 267``` 268 269The memory node addressed by **0x080041ee** is not released after being requested in **MemLeakTest**. 270 271## Memory Corruption Check 272 273 274### Basic Concepts 275 276As an optional function of the kernel, memory corruption check is used to check the integrity of a dynamic memory pool. This mechanism can detect memory corruption errors in the memory pool in a timely manner and provide alerts. It helps reduce problem locating costs and increase troubleshooting efficiency. 277 278 279### Function Configuration 280 281**LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK** specifies the setting of the memory corruption check. This function is disabled by default. To enable the function, set this macro to **1** in **target_config.h**. 282 2831. If this macro is enabled, the memory pool integrity will be checked in real time upon each memory allocation. 284 2852. If this macro is not enabled, you can call **LOS_MemIntegrityCheck** to check the memory pool integrity when required. Using **LOS_MemIntegrityCheck** does not affect the system performance. However, the check accuracy decreases because the node header does not contain the magic number (which is available only when **LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK** is enabled). 286 287This check only detects the corrupted memory node and provides information about the previous node (because memory is contiguous, a node is most likely corrupted by the previous node). To further determine the location where the previous node is requested, you need to enable the memory leak check and use LRs to locate the fault. 288 289> **CAUTION** 290> 291> If memory corruption check is enabled, a magic number is added to the node header, which increases the size of the node header. The real-time integrity check has a great impact on the performance. In performance-sensitive scenarios, you are advised to disable this function and use **LOS_MemIntegrityCheck** to check the memory pool integrity. 292 293 294### Development Guidelines 295 296 297#### How to Develop 298 299Check for memory corruption by calling **LOS_MemIntegrityCheck**. If no memory corruption occurs, **0** is returned and no log is output. If memory corruption occurs, the related log is output. For details, see the output of the following example. 300 301 302#### Development Example 303 304This example implements the following: 305 3061. Request two physically adjacent memory blocks. 307 3082. Use **memset** to construct an out-of-bounds access and overwrites the first four bytes of the next node. 309 3103. Call **LOS_MemIntegrityCheck** to check whether memory corruption occurs. 311 312 313#### Sample Code 314 315The sample code is as follows: 316 317The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **MemIntegrityTest** function is called in **TestTaskEntry**. 318 319When QEMU is running, ensure that the value of **LOSCFG_MEM_FREE_BY_TASKID** in **target_config.h** is **0**. 320 321Because the exception is triggered intentionally, you need to restart QEMU when the execution is complete. For example, open a new terminal and run **killall qemu-system-arm**. 322 323 324``` 325#include <stdio.h> 326#include <string.h> 327#include "los_memory.h" 328#include "los_config.h" 329 330void MemIntegrityTest(void) 331{ 332 /* Request two physically adjacent memory blocks. */ 333 void *ptr1 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8); 334 void *ptr2 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8); 335 /* Construct an out-of-bounds access to cause memory corruption. The memory block of the first node is 8 bytes. Clearing 12 bytes overwrites the header of the second memory node. */ 336 memset(ptr1, 0, 8 + 4); 337 LOS_MemIntegrityCheck(LOSCFG_SYS_HEAP_ADDR); 338} 339``` 340 341 342#### Verification 343 344The log is as follows: 345 346 347``` 348 349/* Error information indicating the field corrupted. In this example, the first four bytes of the next node are cleared, that is, the magic number field is corrupted. */ 350[ERR][IT_TST_INI][OsMemMagicCheckPrint], 1664, memory check error! 351memory used but magic num wrong, magic num = 0x0 352 353 /* Key information about the corrupted node and its previous node, including the address of the previous node, magic number of the node, and sizeAndFlag of the node. In this example, the magic number of the corrupted node is cleared. */ 354 broken node head: 0x2103d7e8 0x0 0x80000020, prev node head: 0x2103c7cc 0xabcddcba 0x80000020 355 356 /*The node LR information can be output only after the memory leak check is enabled. */ 357 broken node head LR info: 358 LR[0]:0x2101906c 359 LR[1]:0x0 360 LR[2]:0x0 361 362 /* Based on the LR information, you can determine where the previous node in requsted in the assembly file and check the use of the node. */ 363 pre node head LR info: 364 LR[0]:0x2101906c 365 LR[1]:0x0 366 LR[2]:0x0 367 368 /* Addresses of the corrupted node and its previous node. */ 369[ERR][IT_TST_INI]Memory integrity check error, cur node: 0x2103d784, pre node: 0x0 370 371 The preceding data may vary depending on the running environment. 372``` 373