kernel-mini-memory-debug.md 16.0 KB
Newer Older
A
Annie_wang 已提交
1
# Memory Debugging
D
duangavin123 已提交
2

A
Annie_wang 已提交
3

D
duangavin123 已提交
4 5 6
The 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.


A
Annie_wang 已提交
7 8 9 10 11 12 13
## Memory Information Statistics


### Basic Concepts

Memory information includes the memory pool size, memory usage, remaining memory size, maximum free memory, memory waterline, number of memory nodes, and fragmentation rate.

A
Annie_wang 已提交
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.
A
Annie_wang 已提交
15

A
Annie_wang 已提交
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
A
Annie_wang 已提交
17

A
Annie_wang 已提交
18
- You can use [APIs for memory management](kernel-mini-basic-memory.md) to scan node information in the memory pool and collect statistics.
A
Annie_wang 已提交
19 20 21 22


### Function Configuration

A
Annie_wang 已提交
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.
A
Annie_wang 已提交
24 25 26 27 28 29 30 31 32 33 34 35


### Development Guidelines


#### How to Develop

Key structure:


```
typedef struct {
A
Annie_wang 已提交
36 37 38 39 40 41 42
    UINT32 totalUsedSize;       // Memory usage of the memory pool.
    UINT32 totalFreeSize;       // Remaining size of the memory pool.
    UINT32 maxFreeNodeSize;     // Maximum size of the free memory block in the memory pool.
    UINT32 usedNodeNum;         // Number of non-free memory blocks in the memory pool.
    UINT32 freeNodeNum;         // Number of free memory blocks in the memory pool.
#if (LOSCFG_MEM_WATERLINE == 1) // The function is enabled by default. To disable it, set this macro to 0 in target_config.h.
    UINT32 usageWaterLine;      // Waterline of the memory pool.
A
Annie_wang 已提交
43 44 45 46
#endif
} LOS_MEM_POOL_STATUS;
```

A
Annie_wang 已提交
47
To 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.
A
Annie_wang 已提交
48

A
Annie_wang 已提交
49
To 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
A
Annie_wang 已提交
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64


#### Development Example

This example implements the following:

1. Create a monitoring task to obtain information about the memory pool.

2. Calls **LOS_MemInfoGet** to obtain the basic information about the memory pool.

3. Calculate the memory usage and fragmentation rate.


#### Sample Code

A
Annie_wang 已提交
65 66 67
The sample code is as follows:

The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **MemTest** function is called in **TestTaskEntry**.
A
Annie_wang 已提交
68 69 70 71 72 73 74 75

```
#include <stdio.h>
#include <string.h>
#include "los_task.h"
#include "los_memory.h"
#include "los_config.h"

A
Annie_wang 已提交
76
#define TEST_TASK_PRIO  5
A
Annie_wang 已提交
77 78 79 80
void MemInfoTaskFunc(void)
{
    LOS_MEM_POOL_STATUS poolStatus = {0};

A
Annie_wang 已提交
81
    /* pool is the memory address of the information to be collected. OS_SYS_MEM_ADDR is used as an example. */
A
Annie_wang 已提交
82 83 84
    void *pool = OS_SYS_MEM_ADDR;
    LOS_MemInfoGet(pool, &poolStatus);
    /* Calculate the fragmentation rate of the memory pool. */
A
Annie_wang 已提交
85
    float fragment = 100 - poolStatus.maxFreeNodeSize * 100.0 / poolStatus.totalFreeSize;
A
Annie_wang 已提交
86
    /* Calculate the memory usage of the memory pool. */
A
Annie_wang 已提交
87 88 89
    float usage = LOS_MemTotalUsedGet(pool) * 100.0 / LOS_MemPoolSizeGet(pool);
    printf("usage = %f, fragment = %f, maxFreeSize = %d, totalFreeSize = %d, waterLine = %d\n", usage, fragment, 
    		poolStatus.maxFreeNodeSize, poolStatus.totalFreeSize, poolStatus.usageWaterLine);
A
Annie_wang 已提交
90 91 92 93 94 95 96 97
}

int MemTest(void)
{
    unsigned int ret;
    unsigned int taskID;
    TSK_INIT_PARAM_S taskStatus = {0};
    taskStatus.pfnTaskEntry = (TSK_ENTRY_FUNC)MemInfoTaskFunc;
A
Annie_wang 已提交
98
    taskStatus.uwStackSize  = LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE;
A
Annie_wang 已提交
99
    taskStatus.pcName       = "memInfo";
A
Annie_wang 已提交
100
    taskStatus.usTaskPrio   = TEST_TASK_PRIO;
A
Annie_wang 已提交
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
    ret = LOS_TaskCreate(&taskID, &taskStatus);
    if (ret != LOS_OK) {
        printf("task create failed\n");
        return -1;
    }
    return 0;
}
```


#### Verification

The result is as follows:


```
A
Annie_wang 已提交
117 118 119
usage = 0.458344, fragment = 0.000000, maxFreeSize = 16474928, totalFreeSize = 16474928, waterLine = 76816

The preceding data may vary depending on the running environment.
A
Annie_wang 已提交
120 121 122 123 124 125 126 127 128 129 130
```
## 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 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

A
Annie_wang 已提交
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**.
A
Annie_wang 已提交
132

A
Annie_wang 已提交
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.
A
Annie_wang 已提交
134

A
Annie_wang 已提交
135 136 137 138 139
**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:

- **LOS_MemAlloc** is also called internally.
- **LOS_MemAlloc** may be encapsulated externally.
- The number of LRs configured by **LOSCFG_MEM_RECORD_LR_CNT** is limited.
A
Annie_wang 已提交
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163

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: <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.


```
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 
```

A
Annie_wang 已提交
164 165
> **CAUTION**
>
A
Annie_wang 已提交
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
> 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:

1. Call **LOS_MemUsedNodeShow** to print information about all nodes.

2. Simulate a memory leak by requesting memory without releasing it.

3. Call **LOS_MemUsedNodeShow** to print information about all nodes.

4. Compare the logs to obtain information about the node where a memory leak occurred.

5. Locate the code based on the LR address.


#### Sample Code

The sample code is as follows:

A
Annie_wang 已提交
188 189 190 191 192 193
The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **MemLeakTest** function is called in **TestTaskEntry**.

When QEMU is running, ensure that the value of **LOSCFG_MEM_FREE_BY_TASKID** in **target_config.h** is **0**.

After 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**.

A
Annie_wang 已提交
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230

```
#include <stdio.h>
#include <string.h>
#include "los_memory.h"
#include "los_config.h"

void MemLeakTest(void)
{
    LOS_MemUsedNodeShow(LOSCFG_SYS_HEAP_ADDR);
    void *ptr1 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8);
    void *ptr2 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8);
    LOS_MemUsedNodeShow(LOSCFG_SYS_HEAP_ADDR);
}
```


#### Verification

The log is as follows:


```
node         size   LR[0]       LR[1]       LR[2]   
0x20001b04:  0x24   0x08001a10  0x080035ce  0x080028fc 
0x20002058:  0x40   0x08002fe8  0x08003626  0x080028fc 
0x200022ac:  0x40   0x08000e0c  0x08000e56  0x0800359e 
0x20002594:  0x120  0x08000e0c  0x08000e56  0x08000c8a 
0x20002aac:  0x56   0x08000e0c  0x08000e56  0x08004220 

node         size   LR[0]       LR[1]       LR[2]   
0x20001b04:  0x24   0x08001a10  0x080035ce  0x080028fc 
0x20002058:  0x40   0x08002fe8  0x08003626  0x080028fc 
0x200022ac:  0x40   0x08000e0c  0x08000e56  0x0800359e 
0x20002594:  0x120  0x08000e0c  0x08000e56  0x08000c8a 
0x20002aac:  0x56   0x08000e0c  0x08000e56  0x08004220 
0x20003ac4:  0x1d   0x08001458  0x080014e0  0x080041e6 
A
Annie_wang 已提交
231 232 233
0x20003ae0:  0x1d   0x080041ee  0x08000cc2  0x00000000

The preceding data may vary depending on the running environment.
A
Annie_wang 已提交
234 235 236 237 238 239 240
```

The difference between the two logs is as follows. The following memory nodes are suspected to have blocks with a memory leak.


```
0x20003ac4:  0x1d   0x08001458  0x080014e0  0x080041e6 
A
Annie_wang 已提交
241 242 243
0x20003ae0:  0x1d   0x080041ee  0x08000cc2  0x00000000

The preceding data may vary depending on the running environment.
A
Annie_wang 已提交
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
```

The following is part of the assembly file:


```
                MemLeakTest:
  0x80041d4: 0xb510         PUSH     {R4, LR}
  0x80041d6: 0x4ca8         LDR.N    R4, [PC, #0x2a0]       ; g_memStart
  0x80041d8: 0x0020         MOVS     R0, R4
  0x80041da: 0xf7fd 0xf93e  BL       LOS_MemUsedNodeShow    ; 0x800145a
  0x80041de: 0x2108         MOVS     R1, #8
  0x80041e0: 0x0020         MOVS     R0, R4
  0x80041e2: 0xf7fd 0xfbd9  BL       LOS_MemAlloc           ; 0x8001998
  0x80041e6: 0x2108         MOVS     R1, #8
  0x80041e8: 0x0020         MOVS     R0, R4
  0x80041ea: 0xf7fd 0xfbd5  BL       LOS_MemAlloc           ; 0x8001998
  0x80041ee: 0x0020         MOVS     R0, R4
  0x80041f0: 0xf7fd 0xf933  BL       LOS_MemUsedNodeShow    ; 0x800145a
  0x80041f4: 0xbd10         POP      {R4, PC}
  0x80041f6: 0x0000         MOVS     R0, R0
A
Annie_wang 已提交
265 266
  
  The preceding data may vary depending on the running environment.
A
Annie_wang 已提交
267 268 269 270 271 272 273 274 275 276 277 278 279 280
```

The memory node addressed by **0x080041ee** is not released after being requested in **MemLeakTest**.

## Memory Corruption Check


### Basic Concepts

As 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.


### Function Configuration

A
Annie_wang 已提交
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**.
A
Annie_wang 已提交
282 283 284

1. If this macro is enabled, the memory pool integrity will be checked in real time upon each memory allocation.

A
Annie_wang 已提交
285
2. 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).
A
Annie_wang 已提交
286 287 288

This 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.

A
Annie_wang 已提交
289 290
> **CAUTION**
>
A
Annie_wang 已提交
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
> 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.


### Development Guidelines


#### How to Develop

Check 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.


#### Development Example

This example implements the following:

1. Request two physically adjacent memory blocks.

2. Use **memset** to construct an out-of-bounds access and overwrites the first four bytes of the next node.

3. Call **LOS_MemIntegrityCheck** to check whether memory corruption occurs.


#### Sample Code

The sample code is as follows:

A
Annie_wang 已提交
317 318 319 320 321 322
The sample code can be compiled and verified in **./kernel/liteos_m/testsuites/src/osTest.c**. The **MemIntegrityTest** function is called in **TestTaskEntry**.

When QEMU is running, ensure that the value of **LOSCFG_MEM_FREE_BY_TASKID** in **target_config.h** is **0**.

Because 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**.

A
Annie_wang 已提交
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347

```
#include <stdio.h>
#include <string.h>
#include "los_memory.h"
#include "los_config.h"

void MemIntegrityTest(void)
{
    /* Request two physically adjacent memory blocks. */
    void *ptr1 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8);
    void *ptr2 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8);
    /* 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. */
    memset(ptr1, 0, 8 + 4);
    LOS_MemIntegrityCheck(LOSCFG_SYS_HEAP_ADDR);
}
```


#### Verification

The log is as follows:


```
A
Annie_wang 已提交
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371

/* 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. */
[ERR][IT_TST_INI][OsMemMagicCheckPrint], 1664, memory check error!
memory used but magic num wrong, magic num = 0x0

 /* 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. */
 broken node head: 0x2103d7e8  0x0  0x80000020, prev node head: 0x2103c7cc  0xabcddcba  0x80000020

 /*The node LR information can be output only after the memory leak check is enabled. */
 broken node head LR info:
 LR[0]:0x2101906c
 LR[1]:0x0
 LR[2]:0x0

 /* 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. */
 pre node head LR info:
 LR[0]:0x2101906c
 LR[1]:0x0
 LR[2]:0x0
 
 /* Addresses of the corrupted node and its previous node. */
[ERR][IT_TST_INI]Memory integrity check error, cur node: 0x2103d784, pre node: 0x0

 The preceding data may vary depending on the running environment.
A
Annie_wang 已提交
372
```