如何为 freertos 的 heap_4 动态内存分配方案增加 heap info 调试信息?

增加调试信息的目的是为了方便排查内存泄漏和内存越界问题,为了排查内存泄漏,需要记录每个内存块的申请者信息,以下是针对内存泄漏问题调试的修改。

  • 修改内存块头部的数据结构,增加字段记录内存申请者的信息和申请的内存大小。
1
2
3
4
5
6
7
typedef struct A_BLOCK_LINK
{
    struct A_BLOCK_LINK * pxNextFreeBlock; /*<< The next free block in the list. */
    size_t xBlockSize;                     /*<< The size of the free block. */
    size_t xWantedSize;
    void *caller;
} BlockLink_t;

xWantedSize 和 caller 是新增的字段,分别用于记录内存分配时候的调用者信息和申请的内存大小。

  • 修改 pvPortMalloc 和 pvPortRealloc 的定义,传入参数增加 caller。
1
2
3
void * pvPortMalloc( size_t xSize , void *caller) PRIVILEGED_FUNCTION;
void * pvPortRealloc( void *p,
                     size_t xSize, void *caller) PRIVILEGED_FUNCTION;
  • 修改 prvHeapInit pvPortMalloc 的实现,增加记录 caller,增加新接口 show_heap_info 查看 heap 的内存使用情况。

在 heap 初始化的时候增加 caller xWantedSize 的初始化。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
static void prvHeapInit( void ) /* PRIVILEGED_FUNCTION */
{
    BlockLink_t * pxFirstFreeBlock;
    uint8_t * pucAlignedHeap;
    size_t uxAddress;
    size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;

    /* Ensure the heap starts on a correctly aligned boundary. */
    uxAddress = ( size_t ) ucHeap;

    if( ( uxAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
    {
        uxAddress += ( portBYTE_ALIGNMENT - 1 );
        uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
        xTotalHeapSize -= uxAddress - ( size_t ) ucHeap;
    }

    pucAlignedHeap = ( uint8_t * ) uxAddress;

    /* xStart is used to hold a pointer to the first item in the list of free
     * blocks.  The void cast is used to prevent compiler warnings. */
    xStart.pxNextFreeBlock = ( void * ) pucAlignedHeap;
    xStart.xBlockSize = ( size_t ) 0;
    xStart.caller = NULL;
    xStart.xWantedSize = 0;

    /* pxEnd is used to mark the end of the list of free blocks and is inserted
     * at the end of the heap space. */
    uxAddress = ( ( size_t ) pucAlignedHeap ) + xTotalHeapSize;
    uxAddress -= xHeapStructSize;
    uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
    pxEnd = ( void * ) uxAddress;
    pxEnd->xBlockSize = 0;
    pxEnd->caller = NULL;
    pxEnd->pxNextFreeBlock = NULL;

    /* To start with there is a single free block that is sized to take up the
     * entire heap space, minus the space taken by pxEnd. */
    pxFirstFreeBlock = ( void * ) pucAlignedHeap;
    pxFirstFreeBlock->xBlockSize = uxAddress - ( size_t ) pxFirstFreeBlock;
    pxFirstFreeBlock->xWantedSize = 0;
    pxFirstFreeBlock->caller = NULL;
    pxFirstFreeBlock->pxNextFreeBlock = pxEnd;

    /* Only one block exists - and it covers the entire usable heap space. */
    xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
    xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
}

在分配内存的时候,记录caller 和 xWantedSize 到内存卡的头部。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
void * pvPortMalloc( size_t xWantedSize , void * caller)
{
    BlockLink_t * pxBlock, * pxPreviousBlock, * pxNewBlockLink;
    void * pvReturn = NULL;
    size_t xAdditionalRequiredSize;
    size_t _xWantedSize = xWantedSize;

    vTaskSuspendAll();
    {
        /* If this is the first call to malloc then the heap will require
         * initialisation to setup the list of free blocks. */
        if( pxEnd == NULL )
        {
            prvHeapInit();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        if( xWantedSize > 0 )
        {
            /* The wanted size must be increased so it can contain a BlockLink_t
             * structure in addition to the requested amount of bytes. Some
             * additional increment may also be needed for alignment. */
            xAdditionalRequiredSize = xHeapStructSize  + portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK );

            if( heapADD_WILL_OVERFLOW( xWantedSize, xAdditionalRequiredSize ) == 0 )
            {
                xWantedSize += xAdditionalRequiredSize;
            }
            else
            {
                xWantedSize = 0;
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        /* Check the block size we are trying to allocate is not so large that the
         * top bit is set.  The top bit of the block size member of the BlockLink_t
         * structure is used to determine who owns the block - the application or
         * the kernel, so it must be free. */
        if( heapBLOCK_SIZE_IS_VALID( xWantedSize ) != 0 )
        {
            if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
            {
                /* Traverse the list from the start (lowest address) block until
                 * one of adequate size is found. */
                pxPreviousBlock = &xStart;
                pxBlock = xStart.pxNextFreeBlock;

                while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
                {
                    pxPreviousBlock = pxBlock;
                    pxBlock = pxBlock->pxNextFreeBlock;
                }

                /* If the end marker was reached then a block of adequate size
                 * was not found. */
                if( pxBlock != pxEnd )
                {
                    /* Return the memory space pointed to - jumping over the
                     * BlockLink_t structure at its start. */
                    pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );

                    /* This block is being returned for use so must be taken out
                     * of the list of free blocks. */
                    pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;

                    /* If the block is larger than required it can be split into
                     * two. */
                    if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
                    {
                        /* This block is to be split into two.  Create a new
                         * block following the number of bytes requested. The void
                         * cast is used to prevent byte alignment warnings from the
                         * compiler. */
                        pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );
                        configASSERT( ( ( ( size_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );

                        /* Calculate the sizes of two blocks split from the
                         * single block. */
                        pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
                        pxNewBlockLink->xWantedSize = 0;
                        pxNewBlockLink->caller = NULL;
                        pxBlock->xBlockSize = xWantedSize;

                        /* Insert the new block into the list of free blocks. */
                        prvInsertBlockIntoFreeList( pxNewBlockLink );
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }

                    

                    xFreeBytesRemaining -= pxBlock->xBlockSize;
                    

                    if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
                    {
                        xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }

              
                    pxBlock->xWantedSize = _xWantedSize;
                    pxBlock->caller = caller;
                    /* The block is being returned - it is allocated and owned
                     * by the application and has no "next" block. */
                    heapALLOCATE_BLOCK( pxBlock );
                    pxBlock->pxNextFreeBlock = NULL;
                    xNumberOfSuccessfulAllocations++;
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        traceMALLOC( pvReturn, xWantedSize );
    }
    xTaskResumeAll();

    #if ( configUSE_MALLOC_FAILED_HOOK == 1 )
    {
        if( pvReturn == NULL )
        {
            vApplicationMallocFailedHook();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    #endif /* if ( configUSE_MALLOC_FAILED_HOOK == 1 ) */

    configASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) portBYTE_ALIGNMENT_MASK ) == 0 );
    return pvReturn;
}

void *pvPortRealloc(void *p,
                    size_t xSize, void * caller)
{
    void *pv = NULL;
    uint8_t *puc = (uint8_t *)p;
    BlockLink_t *pxLink;

    if (p == NULL)
    {
        return NULL;
    }

    puc -= xHeapStructSize;
    pxLink = (void *)puc;

    configASSERT(heapBLOCK_IS_ALLOCATED(pxLink) != 0);
    configASSERT(pxLink->pxNextFreeBlock == NULL);

    pv = pvPortMalloc(xSize, caller);
    if (pv == NULL)
    {
        return NULL;
    }
    memcpy(pv, p, pxLink->xWantedSize);
    vPortFree(p);

    return pv;   
}

遍历 heap 所有的内存块,打印出其调用者、申请内存大小、是已分配的内存块还是空闲的内存块,利用这些信息排查内存泄漏。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void show_heap_info(void)
{
    BlockLink_t * pxLink = NULL;
    uint8_t * pucAlignedHeap;
    size_t uxAddress;
    size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;

    vTaskSuspendAll();
    uxAddress = ( size_t ) ucHeap;

    if( ( uxAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
    {
        uxAddress += ( portBYTE_ALIGNMENT - 1 );
        uxAddress &= ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
        xTotalHeapSize -= uxAddress - ( size_t ) ucHeap;
    }

    pucAlignedHeap = ( uint8_t * ) uxAddress;

    pxLink = (BlockLink_t *)pucAlignedHeap;

    printf("\r\naddress: 0x%p\r\nsize: %d\r\navail: %d\r\npool_start: 0x%p\r\npool_end: 0x%p\r\n",
           ucHeap, xTotalHeapSize, xFreeBytesRemaining, pucAlignedHeap, pxEnd);

    printf("state,block_addr,user_addr,caller,blocksize,wanted_size\r\n");
 
    while (pxLink != pxEnd)
    {
		
        printf("%s, 0x%p, 0x%p, 0x%p,%d,%d\r\n", ((pxLink->xBlockSize & heapBLOCK_ALLOCATED_BITMASK)!=0)? "U":"F", pxLink, (uint8_t *)pxLink+xHeapStructSize, pxLink->caller, (( pxLink->xBlockSize ) & ~heapBLOCK_ALLOCATED_BITMASK), pxLink->xWantedSize);
        pxLink =(BlockLink_t *) (( uint8_t * )pxLink + (( pxLink->xBlockSize ) & ~heapBLOCK_ALLOCATED_BITMASK));
    }

    xTaskResumeAll();
}
  • 利用库打桩机制,替换标准库中的 malloc free realloc 等内存分配函数。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

/************** wrap C library functions **************/
void * __wrap_malloc (size_t size)
{
    void *caller = __builtin_return_address (0);
	return pvPortMalloc(size, caller);
}

void * __wrap__malloc_r (void *p, size_t size)
{
	void *caller = __builtin_return_address (0);
	return pvPortMalloc(size, caller);
}

void __wrap_free (void *pv)
{
	vPortFree(pv);
}

void * __wrap_calloc (size_t a, size_t b)
{
	void *pvReturn;
    void *caller = __builtin_return_address (0);
    pvReturn = pvPortMalloc( a*b, caller);
    if (pvReturn)
    {
        memset(pvReturn, 0, a*b);
    }

    return pvReturn;
}

void * __wrap_realloc (void* pv, size_t size)
{
    void *caller = __builtin_return_address (0);
	return pvPortRealloc(pv, size, caller);
}

void __wrap__free_r (void *p, void *x)
{
  __wrap_free(x);
}

void* __wrap__realloc_r (void *p, void* x, size_t sz)
{
    void *caller = __builtin_return_address (0);
	return pvPortRealloc(x, sz, caller);
}

/*-----------------------------------------------------------*/

gcc 的链接器支持用 –wrap f 参数进行链接时打桩,这个参数告诉链接器,把对符号 f 的引用解析成 __wrap_f。通过这个机制,我们调用malloc的时候,便会替换成我们加了调试信息的__wrap_malloc。另外,再使用 __builtin_return_address 接口获取函数的返回地址并记录,这样就知道是谁申请了这块内存。

最后再添加连接器参数:

1
2
3
4
5
6
7
8
9
sdk_add_link_options(
        -Wl,--wrap=malloc
        -Wl,--wrap=_malloc_r
        -Wl,--wrap=free
        -Wl,--wrap=calloc
        -Wl,--wrap=realloc
        -Wl,--wrap=_free_r
        -Wl,--wrap=_realloc_r
)

对于内存越界问题,可以在每个内存块的末尾增加冗余长度,并填充特定数据,在内存释放的时候检查填充的数据有没有被篡改,以此判断是否存在内存被破坏问题。

  • pvPortMalloc 的修改

在 xWantedSize 的基础上增加一个字节,确保内存块的尾部够空间填充一个特殊数据。然后在将要分配出去的内存块中末尾未使用的数据全部填充为0xfd,填充的长度为 pxBlock->xBlockSize-_xWantedSize-xHeapStructSize。

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
void * pvPortMalloc( size_t xWantedSize , void * caller)
{
    BlockLink_t * pxBlock, * pxPreviousBlock, * pxNewBlockLink;
    void * pvReturn = NULL;
    size_t xAdditionalRequiredSize;
    size_t _xWantedSize = xWantedSize;

    vTaskSuspendAll();
    {
        /* If this is the first call to malloc then the heap will require
         * initialisation to setup the list of free blocks. */
        if( pxEnd == NULL )
        {
            prvHeapInit();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        if( xWantedSize > 0 )
        {
            /* The wanted size must be increased so it can contain a BlockLink_t
             * structure in addition to the requested amount of bytes. Some
             * additional increment may also be needed for alignment. */
            xWantedSize += 1;
            xAdditionalRequiredSize = xHeapStructSize  + portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK );

            if( heapADD_WILL_OVERFLOW( xWantedSize, xAdditionalRequiredSize ) == 0 )
            {
                xWantedSize += xAdditionalRequiredSize;
            }
            else
            {
                xWantedSize = 0;
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        /* Check the block size we are trying to allocate is not so large that the
         * top bit is set.  The top bit of the block size member of the BlockLink_t
         * structure is used to determine who owns the block - the application or
         * the kernel, so it must be free. */
        if( heapBLOCK_SIZE_IS_VALID( xWantedSize ) != 0 )
        {
            if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
            {
                /* Traverse the list from the start (lowest address) block until
                 * one of adequate size is found. */
                pxPreviousBlock = &xStart;
                pxBlock = xStart.pxNextFreeBlock;

                while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != NULL ) )
                {
                    pxPreviousBlock = pxBlock;
                    pxBlock = pxBlock->pxNextFreeBlock;
                }

                /* If the end marker was reached then a block of adequate size
                 * was not found. */
                if( pxBlock != pxEnd )
                {
                    /* Return the memory space pointed to - jumping over the
                     * BlockLink_t structure at its start. */
                    pvReturn = ( void * ) ( ( ( uint8_t * ) pxPreviousBlock->pxNextFreeBlock ) + xHeapStructSize );

                    /* This block is being returned for use so must be taken out
                     * of the list of free blocks. */
                    pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;

                    /* If the block is larger than required it can be split into
                     * two. */
                    if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
                    {
                        /* This block is to be split into two.  Create a new
                         * block following the number of bytes requested. The void
                         * cast is used to prevent byte alignment warnings from the
                         * compiler. */
                        pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );
                        configASSERT( ( ( ( size_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );

                        /* Calculate the sizes of two blocks split from the
                         * single block. */
                        pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
                        pxNewBlockLink->xWantedSize = 0;
                        pxNewBlockLink->caller = NULL;
                        pxBlock->xBlockSize = xWantedSize;

                        /* Insert the new block into the list of free blocks. */
                        prvInsertBlockIntoFreeList( pxNewBlockLink );
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }

                    

                    xFreeBytesRemaining -= pxBlock->xBlockSize;
                    

                    if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
                    {
                        xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }

              
                    pxBlock->xWantedSize = _xWantedSize;
                    pxBlock->caller = caller;
                    int _len = pxBlock->xBlockSize-_xWantedSize-xHeapStructSize;
					uint8_t *_p = (uint8_t *)pxBlock+_xWantedSize+xHeapStructSize;
					while (_len > 0)
					{
						*_p = 0xfd;
						_p++;
						_len--;
					}

                    /* The block is being returned - it is allocated and owned
                     * by the application and has no "next" block. */
                    heapALLOCATE_BLOCK( pxBlock );
                    pxBlock->pxNextFreeBlock = NULL;
                    xNumberOfSuccessfulAllocations++;
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }

        traceMALLOC( pvReturn, xWantedSize );
    }
    xTaskResumeAll();

    #if ( configUSE_MALLOC_FAILED_HOOK == 1 )
    {
        if( pvReturn == NULL )
        {
            vApplicationMallocFailedHook();
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    #endif /* if ( configUSE_MALLOC_FAILED_HOOK == 1 ) */

    configASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) portBYTE_ALIGNMENT_MASK ) == 0 );
    return pvReturn;
}

在释放内存的时候检查内存块的填充数据是否有被篡改,如果有被篡改则说明出现了内存越界问题,可以打印当前内存块的 caller 信息和 dump 整个 block 数据,然后立再触发 ASSERT。 除了在内存释放的时候检查heap是否有越界,也可以在任务上下文切换的时候检查,不过这样会增加任务调度的开销,影响任务切换的效率。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

void vPortFree( void * pv )
{
    uint8_t * puc = ( uint8_t * ) pv;
    BlockLink_t * pxLink;

    if( pv != NULL )
    {
        /* The memory being freed will have an BlockLink_t structure immediately
         * before it. */
        puc -= xHeapStructSize;

        /* This casting is to keep the compiler from issuing warnings. */
        pxLink = ( void * ) puc;

        configASSERT( heapBLOCK_IS_ALLOCATED( pxLink ) != 0 );
        configASSERT( pxLink->pxNextFreeBlock == NULL );

        if( heapBLOCK_IS_ALLOCATED( pxLink ) != 0 )
        {
            if( pxLink->pxNextFreeBlock == NULL )
            {
                /* The block is being returned to the heap - it is no longer
                 * allocated. */
                heapFREE_BLOCK( pxLink );
                #if ( configHEAP_CLEAR_MEMORY_ON_FREE == 1 )
                {
                    ( void ) memset( puc + xHeapStructSize, 0, pxLink->xBlockSize - xHeapStructSize );
                }
                #endif

                vTaskSuspendAll();
                int _len = pxLink->xBlockSize - pxLink->xWantedSize - xHeapStructSize;
				uint8_t *_p = (uint8_t *)pxLink + pxLink->xWantedSize + xHeapStructSize;
				while (_len > 0)
				{
					if(*_p != 0xfd)
					{
						printf("mem crash,block:0x%p,caller: 0x%p, 0x%02x\r\n", pxLink, pxLink->caller, *_p);
					}
					configASSERT( (*_p == 0xfd ) );
					_p++;
					_len--;
				}

                {
                    /* Add this block to the list of free blocks. */
                    xFreeBytesRemaining += pxLink->xBlockSize;
                    traceFREE( pv, pxLink->xBlockSize );
                    pxLink->xWantedSize = 0;
                    prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
                    xNumberOfSuccessfulFrees++;
                }
                /*( void ) */xTaskResumeAll();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
}

增加 heap info 信息会增加内存分配的开销,导致实际可以使用的 heap 内存变小,在内存较小的机器,应在正式软件上关闭 heap info 信息,以节省内存。

heap info 调试案例

内存泄漏问题案例

案例1

打开 mqtt 之前的 heap info:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
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
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
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
317
318
319
320
321
322
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
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
address: 0x40aae8
size: 152856
avail: 45288
pool_start: 0x40aae8
pool_end: 0x42fff0
state,block_addr,user_addr,caller,blocksize,wanted_size
U,0x40aae8,0x40abe8,0x1b695,4112,4096
U,0x40baf8,0x40bbf8,0x1b6b5,40,20
U,0x40bb20,0x40bc20,0x1b695,528,512
U,0x40bd30,0x40be30,0x1b6b5,40,20
U,0x40bd58,0x40be58,0x1b695,4112,4096
U,0x40cd68,0x40ce68,0x1b6b5,40,20
U,0x40cd90,0x40ce90,0x1b695,528,512
U,0x40cfa0,0x40d0a0,0x1b6b5,40,20
U,0x40cfc8,0x40d0c8,0x7eab8,96,80
U,0x40d028,0x40d128,0x7e8ac,96,80
U,0x40d088,0x40d188,0x28319,112,92
U,0x40d0f8,0x40d1f8,0x28441,96,80
U,0x40d158,0x40d258,0x7eab8,96,80
U,0x40d1b8,0x40d2b8,0x7eab8,96,80
U,0x40d218,0x40d318,0x28319,112,92
U,0x40d288,0x40d388,0x28441,96,80
U,0x40d2e8,0x40d3e8,0x7eab8,96,80
U,0x40d348,0x40d448,0x7eab8,96,80
U,0x40d3a8,0x40d4a8,0x28319,112,92
U,0x40d418,0x40d518,0x28441,96,80
U,0x40d478,0x40d578,0x7eab8,96,80
U,0x40d4d8,0x40d5d8,0x7eab8,96,80
U,0x40d538,0x40d638,0x803f4,112,92
U,0x40d5a8,0x40d6a8,0xa4be5,56,36
U,0x40d5e0,0x40d6e0,0x9fb53,48,28
U,0x40d610,0x40d710,0xb22f3,760,744
U,0x40d908,0x40da08,0x7f51c,1040,1024
U,0x40dd18,0x40de18,0x7f51c,112,92
U,0x40dd88,0x40de88,0x7fe1c,288,272
U,0x40dea8,0x40dfa8,0x7fefc,3088,3072
U,0x40eab8,0x40ebb8,0x7fefc,112,92
U,0x40eb28,0x40ec28,0x15769,32,16
U,0x40eb48,0x40ec48,0x15789,128,108
U,0x40ebc8,0x40ecc8,0x157a9,136,114
U,0x40ec50,0x40ed50,0x80808,120,100
U,0x40ecc8,0x40edc8,0x803f4,1040,1024
U,0x40f0d8,0x40f1d8,0x803f4,112,92
U,0x40f148,0x40f248,0x7e8ac,96,80
U,0x40f1a8,0x40f2a8,0x803f4,4112,4096
U,0x4101b8,0x4102b8,0x803f4,112,92
U,0x410228,0x410328,0x28441,96,80
U,0x410288,0x410388,0x1405f,64,40
U,0x4102c8,0x4103c8,0xa01ef,40,22
U,0x4102f0,0x4103f0,0x80c7c,72,44
U,0x410338,0x410438,0x83c1b,24,8
U,0x410350,0x410450,0x83c1b,40,4
U,0x410378,0x410478,0xa1b0d,64,32
U,0x4103b8,0x4104b8,0x34f21,1040,1024
U,0x4107c8,0x4108c8,0x9f79d,40,9
U,0x4107f0,0x4108f0,0x9a079,192,172
U,0x4108b0,0x4109b0,0x9bf95,40,22
U,0x4108d8,0x4109d8,0x99f8f,224,208
U,0x4109b8,0x410ab8,0x9c46f,64,48
U,0x4109f8,0x410af8,0x9dfef,40,22
U,0x410a20,0x410b20,0x6e705,32,9
U,0x410a40,0x410b40,0xa01ef,56,22
U,0x410a78,0x410b78,0x7eab8,96,80
U,0x410ad8,0x410bd8,0x7eab8,96,80
U,0x410b38,0x410c38,0x28319,224,208
U,0x410c18,0x410d18,0x7eab8,96,80
U,0x410c78,0x410d78,0x285a9,2064,2048
U,0x411488,0x411588,0x285a9,112,92
U,0x4114f8,0x4115f8,0x80808,1120,1104
U,0x411958,0x411a58,0x803f4,4112,4096
U,0x412968,0x412a68,0x803f4,112,92
U,0x4129d8,0x412ad8,0x9d659,72,52
U,0x412a20,0x412b20,0x7e8ac,96,80
U,0x412a80,0x412b80,0x80808,1632,1616
U,0x4130e0,0x4131e0,0x803f4,2064,2048
U,0x4138f0,0x4139f0,0x803f4,112,92
U,0x413960,0x413a60,0x80808,256,240
U,0x413a60,0x413b60,0x803f4,1168,1152
U,0x413ef0,0x413ff0,0xa46c5,952,936
U,0x4142a8,0x4143a8,0xb1ff7,56,4
U,0x4142e0,0x4143e0,0x80808,176,160
U,0x414390,0x414490,0x803f4,4112,4096
U,0x4153a0,0x4154a0,0x803f4,112,92
U,0x415410,0x415510,0x7e8ac,96,80
U,0x415470,0x415570,0x803f4,112,92
U,0x4154e0,0x4155e0,0x80808,1296,1280
U,0x4159f0,0x415af0,0x803f4,112,92
U,0x415a60,0x415b60,0x7eab8,96,80
U,0x415ac0,0x415bc0,0x7e8ac,96,80
U,0x415b20,0x415c20,0x803f4,136,92
U,0x415ba8,0x415ca8,0x1405f,56,40
U,0x415be0,0x415ce0,0x1405f,56,40
U,0x415c18,0x415d18,0x13ed5,24,5
U,0x415c30,0x415d30,0x1405f,56,40
U,0x415c68,0x415d68,0x13ed5,24,8
U,0x415c80,0x415d80,0x1405f,56,40
U,0x415cb8,0x415db8,0x13ed5,24,7
U,0x415cd0,0x415dd0,0x1405f,56,40
U,0x415d08,0x415e08,0x13ed5,24,2
U,0x415d20,0x415e20,0x1405f,56,40
U,0x415d58,0x415e58,0x13ed5,24,7
U,0x415d70,0x415e70,0x1405f,56,40
U,0x415da8,0x415ea8,0x13ed5,32,12
U,0x415dc8,0x415ec8,0x1405f,56,40
U,0x415e00,0x415f00,0x13ed5,24,8
U,0x415e18,0x415f18,0x1405f,56,40
U,0x415e50,0x415f50,0x13ed5,32,11
U,0x415e70,0x415f70,0x13ed5,32,12
U,0x415e90,0x415f90,0x1405f,56,40
U,0x415ec8,0x415fc8,0x13ed5,32,13
U,0x415ee8,0x415fe8,0x13ed5,56,33
U,0x415f20,0x416020,0x1405f,56,40
U,0x415f58,0x416058,0x13ed5,32,11
U,0x415f78,0x416078,0x13ed5,24,8
U,0x415f90,0x416090,0x1405f,56,40
U,0x415fc8,0x4160c8,0x13ed5,24,7
U,0x415fe0,0x4160e0,0x1405f,56,40
U,0x416018,0x416118,0x13ed5,24,4
U,0x416030,0x416130,0x1405f,56,40
U,0x416068,0x416168,0x13ed5,24,2
U,0x416080,0x416180,0x13ed5,32,12
U,0x4160a0,0x4161a0,0x1405f,56,40
U,0x4160d8,0x4161d8,0x13ed5,24,2
U,0x4160f0,0x4161f0,0x13ed5,32,13
U,0x416110,0x416210,0x1405f,56,40
U,0x416148,0x416248,0x13ed5,24,4
U,0x416160,0x416260,0x1405f,56,40
U,0x416198,0x416298,0x13ed5,24,2
U,0x4161b0,0x4162b0,0x13ed5,32,12
U,0x4161d0,0x4162d0,0x1405f,56,40
U,0x416208,0x416308,0x13ed5,24,2
U,0x416220,0x416320,0x13ed5,32,13
U,0x416240,0x416340,0x1405f,56,40
U,0x416278,0x416378,0x13ed5,24,4
U,0x416290,0x416390,0x1405f,56,40
U,0x4162c8,0x4163c8,0x13ed5,24,2
U,0x4162e0,0x4163e0,0x1405f,56,40
U,0x416318,0x416418,0x13ed5,24,8
U,0x416330,0x416430,0x1405f,56,40
U,0x416368,0x416468,0x13ed5,32,11
U,0x416388,0x416488,0x13ed5,32,12
U,0x4163a8,0x4164a8,0x1405f,56,40
U,0x4163e0,0x4164e0,0x13ed5,32,13
U,0x416400,0x416500,0x13ed5,56,33
U,0x416438,0x416538,0x1405f,56,40
U,0x416470,0x416570,0x13ed5,32,11
U,0x416490,0x416590,0x13ed5,24,8
U,0x4164a8,0x4165a8,0x1405f,56,40
U,0x4164e0,0x4165e0,0x13ed5,24,7
U,0x4164f8,0x4165f8,0x1405f,56,40
U,0x416530,0x416630,0x13ed5,32,12
U,0x416550,0x416650,0x1405f,56,40
U,0x416588,0x416688,0x13ed5,24,7
U,0x4165a0,0x4166a0,0x1405f,56,40
U,0x4165d8,0x4166d8,0x13ed5,24,4
U,0x4165f0,0x4166f0,0x1405f,56,40
U,0x416628,0x416728,0x13ed5,24,2
U,0x416640,0x416740,0x13ed5,40,19
U,0x416668,0x416768,0x1405f,56,40
U,0x4166a0,0x4167a0,0x13ed5,24,2
U,0x4166b8,0x4167b8,0x13ed5,32,12
U,0x4166d8,0x4167d8,0x1405f,56,40
U,0x416710,0x416810,0x13ed5,24,4
U,0x416728,0x416828,0x1405f,56,40
U,0x416760,0x416860,0x13ed5,24,2
U,0x416778,0x416878,0x13ed5,40,19
U,0x4167a0,0x4168a0,0x1405f,56,40
U,0x4167d8,0x4168d8,0x13ed5,24,2
U,0x4167f0,0x4168f0,0x13ed5,32,12
U,0x416810,0x416910,0x1405f,56,40
U,0x416848,0x416948,0x13ed5,24,4
U,0x416860,0x416960,0x1405f,56,40
U,0x416898,0x416998,0x13ed5,24,2
U,0x4168b0,0x4169b0,0x1405f,56,40
U,0x4168e8,0x4169e8,0x13ed5,24,8
U,0x416900,0x416a00,0x1405f,56,40
U,0x416938,0x416a38,0x13ed5,32,11
U,0x416958,0x416a58,0x13ed5,32,12
U,0x416978,0x416a78,0x1405f,56,40
U,0x4169b0,0x416ab0,0x13ed5,32,13
U,0x4169d0,0x416ad0,0x13ed5,56,33
U,0x416a08,0x416b08,0x1405f,56,40
U,0x416a40,0x416b40,0x13ed5,32,11
U,0x416a60,0x416b60,0x13ed5,24,8
U,0x416a78,0x416b78,0x1405f,56,40
U,0x416ab0,0x416bb0,0x13ed5,24,7
U,0x416ac8,0x416bc8,0x1405f,56,40
U,0x416b00,0x416c00,0x13ed5,32,12
U,0x416b20,0x416c20,0x1405f,56,40
U,0x416b58,0x416c58,0x13ed5,24,7
U,0x416b70,0x416c70,0x1405f,56,40
U,0x416ba8,0x416ca8,0x13ed5,24,4
U,0x416bc0,0x416cc0,0x1405f,56,40
U,0x416bf8,0x416cf8,0x13ed5,24,2
U,0x416c10,0x416d10,0x13ed5,40,19
U,0x416c38,0x416d38,0x1405f,56,40
U,0x416c70,0x416d70,0x13ed5,24,2
U,0x416c88,0x416d88,0x13ed5,40,20
U,0x416cb0,0x416db0,0x1405f,56,40
U,0x416ce8,0x416de8,0x13ed5,24,4
U,0x416d00,0x416e00,0x1405f,56,40
U,0x416d38,0x416e38,0x13ed5,24,2
U,0x416d50,0x416e50,0x13ed5,40,19
U,0x416d78,0x416e78,0x1405f,56,40
U,0x416db0,0x416eb0,0x13ed5,24,2
U,0x416dc8,0x416ec8,0x13ed5,40,20
U,0x416df0,0x416ef0,0x1405f,56,40
U,0x416e28,0x416f28,0x13ed5,24,4
U,0x416e40,0x416f40,0x1405f,56,40
U,0x416e78,0x416f78,0x13ed5,24,2
U,0x416e90,0x416f90,0x1405f,56,40
U,0x416ec8,0x416fc8,0x13ed5,24,8
U,0x416ee0,0x416fe0,0x1405f,56,40
U,0x416f18,0x417018,0x13ed5,32,11
U,0x416f38,0x417038,0x13ed5,32,12
U,0x416f58,0x417058,0x1405f,56,40
U,0x416f90,0x417090,0x13ed5,32,13
U,0x416fb0,0x4170b0,0x13ed5,56,33
U,0x416fe8,0x4170e8,0x1405f,56,40
U,0x417020,0x417120,0x13ed5,32,11
U,0x417040,0x417140,0x13ed5,32,13
U,0x417060,0x417160,0x1405f,56,40
U,0x417098,0x417198,0x13ed5,24,7
U,0x4170b0,0x4171b0,0x1405f,56,40
U,0x4170e8,0x4171e8,0x13ed5,32,12
U,0x417108,0x417208,0x1405f,56,40
U,0x417140,0x417240,0x13ed5,24,7
U,0x417158,0x417258,0x1405f,56,40
U,0x417190,0x417290,0x13ed5,24,4
U,0x4171a8,0x4172a8,0x1405f,56,40
U,0x4171e0,0x4172e0,0x13ed5,24,2
U,0x4171f8,0x4172f8,0x13ed5,40,21
U,0x417220,0x417320,0x1405f,56,40
U,0x417258,0x417358,0x13ed5,24,2
U,0x417270,0x417370,0x13ed5,40,22
U,0x417298,0x417398,0x1405f,56,40
U,0x4172d0,0x4173d0,0x13ed5,24,4
U,0x4172e8,0x4173e8,0x1405f,56,40
U,0x417320,0x417420,0x13ed5,24,2
U,0x417338,0x417438,0x13ed5,40,21
U,0x417360,0x417460,0x1405f,56,40
U,0x417398,0x417498,0x13ed5,24,2
U,0x4173b0,0x4174b0,0x13ed5,40,22
U,0x4173d8,0x4174d8,0x1405f,56,40
U,0x417410,0x417510,0x13ed5,24,4
U,0x417428,0x417528,0x1405f,56,40
U,0x417460,0x417560,0x13ed5,24,2
U,0x417478,0x417578,0x1405f,56,40
U,0x4174b0,0x4175b0,0x13ed5,24,8
U,0x4174c8,0x4175c8,0x1405f,56,40
U,0x417500,0x417600,0x13ed5,32,11
U,0x417520,0x417620,0x13ed5,32,12
U,0x417540,0x417640,0x1405f,56,40
U,0x417578,0x417678,0x13ed5,32,13
U,0x417598,0x417698,0x13ed5,56,33
U,0x4175d0,0x4176d0,0x1405f,56,40
U,0x417608,0x417708,0x13ed5,32,11
U,0x417628,0x417728,0x13ed5,32,13
U,0x417648,0x417748,0x1405f,56,40
U,0x417680,0x417780,0x13ed5,24,7
U,0x417698,0x417798,0x1405f,56,40
U,0x4176d0,0x4177d0,0x13ed5,32,12
U,0x4176f0,0x4177f0,0x1405f,56,40
U,0x417728,0x417828,0x13ed5,24,7
U,0x417740,0x417840,0x1405f,56,40
U,0x417778,0x417878,0x13ed5,24,4
U,0x417790,0x417890,0x1405f,56,40
U,0x4177c8,0x4178c8,0x13ed5,24,2
U,0x4177e0,0x4178e0,0x13ed5,40,21
U,0x417808,0x417908,0x1405f,56,40
U,0x417840,0x417940,0x13ed5,24,2
U,0x417858,0x417958,0x13ed5,40,22
U,0x417880,0x417980,0x1405f,56,40
U,0x4178b8,0x4179b8,0x13ed5,24,4
U,0x4178d0,0x4179d0,0x1405f,56,40
U,0x417908,0x417a08,0x13ed5,24,2
U,0x417920,0x417a20,0x13ed5,40,21
U,0x417948,0x417a48,0x1405f,56,40
U,0x417980,0x417a80,0x13ed5,24,2
U,0x417998,0x417a98,0x13ed5,40,22
U,0x4179c0,0x417ac0,0x1405f,56,40
U,0x4179f8,0x417af8,0x13ed5,24,4
U,0x417a10,0x417b10,0x1405f,56,40
U,0x417a48,0x417b48,0x13ed5,24,8
U,0x417a60,0x417b60,0x1405f,56,40
U,0x417a98,0x417b98,0x1405f,56,40
U,0x417ad0,0x417bd0,0x13ed5,24,8
U,0x417ae8,0x417be8,0x1405f,56,40
U,0x417b20,0x417c20,0x13ed5,32,9
U,0x417b40,0x417c40,0x1405f,56,40
U,0x417b78,0x417c78,0x13ed5,32,9
U,0x417b98,0x417c98,0x1405f,56,40
U,0x417bd0,0x417cd0,0x13ed5,24,6
U,0x417be8,0x417ce8,0x1405f,56,40
U,0x417c20,0x417d20,0x1405f,56,40
U,0x417c58,0x417d58,0x13ed5,24,8
U,0x417c70,0x417d70,0x1405f,56,40
U,0x417ca8,0x417da8,0x13ed5,32,9
U,0x417cc8,0x417dc8,0x1405f,56,40
U,0x417d00,0x417e00,0x13ed5,32,9
U,0x417d20,0x417e20,0x1405f,56,40
U,0x417d58,0x417e58,0x13ed5,24,6
U,0x417d70,0x417e70,0x1405f,56,40
U,0x417da8,0x417ea8,0x1405f,56,40
U,0x417de0,0x417ee0,0x13ed5,24,8
U,0x417df8,0x417ef8,0x1405f,56,40
U,0x417e30,0x417f30,0x13ed5,32,9
U,0x417e50,0x417f50,0x1405f,56,40
U,0x417e88,0x417f88,0x13ed5,32,9
U,0x417ea8,0x417fa8,0x1405f,56,40
U,0x417ee0,0x417fe0,0x13ed5,24,6
U,0x417ef8,0x417ff8,0x1405f,56,40
U,0x417f30,0x418030,0x1405f,56,40
U,0x417f68,0x418068,0x13ed5,24,8
U,0x417f80,0x418080,0x1405f,56,40
U,0x417fb8,0x4180b8,0x13ed5,32,9
U,0x417fd8,0x4180d8,0x1405f,56,40
U,0x418010,0x418110,0x13ed5,32,9
U,0x418030,0x418130,0x1405f,56,40
U,0x418068,0x418168,0x13ed5,24,6
U,0x418080,0x418180,0x1405f,56,40
U,0x4180b8,0x4181b8,0x1405f,56,40
U,0x4180f0,0x4181f0,0x13ed5,24,8
U,0x418108,0x418208,0x1405f,56,40
U,0x418140,0x418240,0x13ed5,32,9
U,0x418160,0x418260,0x1405f,56,40
U,0x418198,0x418298,0x13ed5,32,9
F,0x4181b8,0x4182b8,0x9594d,80,63
U,0x418208,0x418308,0x1405f,56,40
U,0x418240,0x418340,0x13ed5,32,10
U,0x418260,0x418360,0x1405f,56,40
U,0x418298,0x418398,0x13ed5,24,2
U,0x4182b0,0x4183b0,0x1405f,56,40
U,0x4182e8,0x4183e8,0x13ed5,32,9
U,0x418308,0x418408,0x1405f,56,40
U,0x418340,0x418440,0x13ed5,24,5
U,0x418358,0x418458,0x1405f,56,40
U,0x418390,0x418490,0x13ed5,24,8
U,0x4183a8,0x4184a8,0x1405f,56,40
U,0x4183e0,0x4184e0,0x13ed5,24,5
U,0x4183f8,0x4184f8,0x1405f,56,40
U,0x418430,0x418530,0x13ed5,24,5
U,0x418448,0x418548,0x13ed5,24,1
U,0x418460,0x418560,0x1405f,56,40
U,0x418498,0x418598,0x13ed5,24,7
U,0x4184b0,0x4185b0,0x1405f,56,40
U,0x4184e8,0x4185e8,0x13ed5,24,2
U,0x418500,0x418600,0x1405f,56,40
U,0x418538,0x418638,0x13ed5,32,9
U,0x418558,0x418658,0x1405f,56,40
U,0x418590,0x418690,0x13ed5,24,5
U,0x4185a8,0x4186a8,0x1405f,56,40
U,0x4185e0,0x4186e0,0x13ed5,24,8
U,0x4185f8,0x4186f8,0x1405f,56,40
U,0x418630,0x418730,0x13ed5,24,5
U,0x418648,0x418748,0x1405f,56,40
U,0x418680,0x418780,0x13ed5,24,5
U,0x418698,0x418798,0x13ed5,24,1
U,0x4186b0,0x4187b0,0x1405f,56,40
U,0x4186e8,0x4187e8,0x13ed5,24,7
U,0x418700,0x418800,0x1405f,56,40
U,0x418738,0x418838,0x13ed5,24,2
U,0x418750,0x418850,0x1405f,56,40
U,0x418788,0x418888,0x13ed5,32,9
U,0x4187a8,0x4188a8,0x1405f,56,40
U,0x4187e0,0x4188e0,0x13ed5,24,5
U,0x4187f8,0x4188f8,0x1405f,56,40
U,0x418830,0x418930,0x13ed5,24,8
U,0x418848,0x418948,0x1405f,56,40
U,0x418880,0x418980,0x13ed5,24,5
U,0x418898,0x418998,0x1405f,56,40
U,0x4188d0,0x4189d0,0x13ed5,24,5
U,0x4188e8,0x4189e8,0x13ed5,24,1
U,0x418900,0x418a00,0x1405f,56,40
U,0x418938,0x418a38,0x13ed5,24,7
U,0x418950,0x418a50,0x3dc13,2720,2704
U,0x4193f0,0x4194f0,0x803f4,3088,3072
U,0x41a000,0x41a100,0x803f4,3088,3072
U,0x41ac10,0x41ad10,0x80808,896,880
U,0x41af90,0x41b090,0x803f4,1040,1024
U,0x41b3a0,0x41b4a0,0x803f4,12304,12288
U,0x41e3b0,0x41e4b0,0x803f4,112,92
U,0x41e420,0x41e520,0x80808,1296,1280
U,0x41e930,0x41ea30,0x803f4,5136,5120
U,0x41fd40,0x41fe40,0x803f4,112,92
U,0x41fdb0,0x41feb0,0x803f4,4112,4096
U,0x420dc0,0x420ec0,0x803f4,112,92
F,0x420e30,0x420f30,0x956db,64,36
U,0x420e70,0x420f70,0x42d97,40,20
U,0x420e98,0x420f98,0x7eab8,96,80
U,0x420ef8,0x420ff8,0x42d97,40,20
U,0x420f20,0x421020,0x7eab8,96,80
U,0x420f80,0x421080,0x42d97,40,20
U,0x420fa8,0x4210a8,0x7eab8,96,80
U,0x421008,0x421108,0x42d97,40,20
U,0x421030,0x421130,0x7eab8,96,80
U,0x421090,0x421190,0x42d97,40,20
U,0x4210b8,0x4211b8,0x7eab8,96,80
U,0x421118,0x421218,0x42d97,40,20
U,0x421140,0x421240,0x7eab8,96,80
U,0x4211a0,0x4212a0,0x7eab8,96,80
U,0x421200,0x421300,0x80c7c,64,44
U,0x421240,0x421340,0x7e8ac,96,80
U,0x4212a0,0x4213a0,0x7eab8,96,80
U,0x421300,0x421400,0x7e8ac,96,80
U,0x421360,0x421460,0x7e8ac,96,80
U,0x4213c0,0x4214c0,0x7e8ac,96,80
U,0x421420,0x421520,0x803f4,1040,1024
U,0x421830,0x421930,0x803f4,112,92
U,0x4218a0,0x4219a0,0x803f4,1040,1024
U,0x421cb0,0x421db0,0x803f4,112,92
U,0x421d20,0x421e20,0x7e8ac,96,80
U,0x421d80,0x421e80,0x7eab8,96,80
U,0x421de0,0x421ee0,0x961bb,24,4
U,0x421df8,0x421ef8,0x97b51,376,360
U,0x421f70,0x422070,0x6e705,32,11
U,0x421f90,0x422090,0x9642b,328,312
U,0x4220d8,0x4221d8,0x96435,472,456
U,0x4222b0,0x4223b0,0x96455,24,4
U,0x4222c8,0x4223c8,0x6e705,32,9
U,0x4222e8,0x4223e8,0x97b9d,24,4
U,0x422300,0x422400,0x97aa1,288,268
U,0x422420,0x422520,0x97e8b,24,4
U,0x422438,0x422538,0xa4c29,24,4
U,0x422450,0x422550,0x9ec37,88,72
U,0x4224a8,0x4225a8,0x95a9f,48,28
U,0x4224d8,0x4225d8,0x95a9f,48,28
U,0x422508,0x422608,0x9ef85,56,40
U,0x422540,0x422640,0x95a9f,48,28
F,0x422570,0x422670,0x95943,32,16
U,0x422590,0x422690,0xaf3ed,48,12
U,0x4225c0,0x4226c0,0x9d865,72,56
U,0x422608,0x422708,0x9d88b,1472,1456
U,0x422bc8,0x422cc8,0x9d893,64,48
U,0x422c08,0x422d08,0x986b3,40,20
U,0x422c30,0x422d30,0x986e7,112,96
U,0x422ca0,0x422da0,0x96559,104,88
U,0x422d08,0x422e08,0xb1e05,360,342
U,0x422e70,0x422f70,0x83c1b,48,26
F,0x422ea0,0x422fa0,0x9594d,216,130
U,0x422f78,0x423078,0x140f3,40,6
U,0x422fa0,0x4230a0,0x9fe83,96,80
F,0x423000,0x423100,0x8c255,176,130
U,0x4230b0,0x4231b0,0x83c1b,24,1
U,0x4230c8,0x4231c8,0x83c1b,40,20
F,0x4230f0,0x4231f0,0x812b7,40,20
U,0x423118,0x423218,0xb25ff,496,476
U,0x423308,0x423408,0x9e865,88,72
U,0x423360,0x423460,0x95a9f,48,28
U,0x423390,0x423490,0x95a9f,48,28
U,0x4233c0,0x4234c0,0xa4883,56,40
U,0x4233f8,0x4234f8,0xa350b,112,96
U,0x423468,0x423568,0xb0193,1048,1028
U,0x423880,0x423980,0xaf9f7,40,20
U,0x4238a8,0x4239a8,0x9d865,72,56
U,0x4238f0,0x4239f0,0x9d88b,1472,1456
U,0x423eb0,0x423fb0,0x9d893,64,48
U,0x423ef0,0x423ff0,0x9ef85,56,40
U,0x423f28,0x424028,0x95a9f,48,28
U,0x423f58,0x424058,0x9fa4f,64,48
U,0x423f98,0x424098,0x9f79d,32,9
U,0x423fb8,0x4240b8,0x6e705,32,9
U,0x423fd8,0x4240d8,0xb1fa5,144,128
F,0x424068,0x424168,0x9e9a1,3200,512
U,0x424ce8,0x424de8,0x803f4,2064,2048
U,0x4254f8,0x4255f8,0x803f4,112,92
F,0x425568,0x425668,0x95b35,32,16
U,0x425588,0x425688,0x803f4,2064,2048
U,0x425d98,0x425e98,0x803f4,112,92
F,0x425e08,0x425f08,0x14d11,41448,1932

打开 mqtt,然后再关闭 mqtt 之后的 heap info:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
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
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
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
317
318
319
320
321
322
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
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
address: 0x40aae8
size: 152856
avail: 43120
pool_start: 0x40aae8
pool_end: 0x42fff0
state,block_addr,user_addr,caller,blocksize,wanted_size
U,0x40aae8,0x40abe8,0x1b695,4112,4096
U,0x40baf8,0x40bbf8,0x1b6b5,40,20
U,0x40bb20,0x40bc20,0x1b695,528,512
U,0x40bd30,0x40be30,0x1b6b5,40,20
U,0x40bd58,0x40be58,0x1b695,4112,4096
U,0x40cd68,0x40ce68,0x1b6b5,40,20
U,0x40cd90,0x40ce90,0x1b695,528,512
U,0x40cfa0,0x40d0a0,0x1b6b5,40,20
U,0x40cfc8,0x40d0c8,0x7eab8,96,80
U,0x40d028,0x40d128,0x7e8ac,96,80
U,0x40d088,0x40d188,0x28319,112,92
U,0x40d0f8,0x40d1f8,0x28441,96,80
U,0x40d158,0x40d258,0x7eab8,96,80
U,0x40d1b8,0x40d2b8,0x7eab8,96,80
U,0x40d218,0x40d318,0x28319,112,92
U,0x40d288,0x40d388,0x28441,96,80
U,0x40d2e8,0x40d3e8,0x7eab8,96,80
U,0x40d348,0x40d448,0x7eab8,96,80
U,0x40d3a8,0x40d4a8,0x28319,112,92
U,0x40d418,0x40d518,0x28441,96,80
U,0x40d478,0x40d578,0x7eab8,96,80
U,0x40d4d8,0x40d5d8,0x7eab8,96,80
U,0x40d538,0x40d638,0x803f4,112,92
U,0x40d5a8,0x40d6a8,0xa4be5,56,36
U,0x40d5e0,0x40d6e0,0x9fb53,48,28
U,0x40d610,0x40d710,0xb22f3,760,744
U,0x40d908,0x40da08,0x7f51c,1040,1024
U,0x40dd18,0x40de18,0x7f51c,112,92
U,0x40dd88,0x40de88,0x7fe1c,288,272
U,0x40dea8,0x40dfa8,0x7fefc,3088,3072
U,0x40eab8,0x40ebb8,0x7fefc,112,92
U,0x40eb28,0x40ec28,0x15769,32,16
U,0x40eb48,0x40ec48,0x15789,128,108
U,0x40ebc8,0x40ecc8,0x157a9,136,114
U,0x40ec50,0x40ed50,0x80808,120,100
U,0x40ecc8,0x40edc8,0x803f4,1040,1024
U,0x40f0d8,0x40f1d8,0x803f4,112,92
U,0x40f148,0x40f248,0x7e8ac,96,80
U,0x40f1a8,0x40f2a8,0x803f4,4112,4096
U,0x4101b8,0x4102b8,0x803f4,112,92
U,0x410228,0x410328,0x28441,96,80
U,0x410288,0x410388,0x1405f,64,40
U,0x4102c8,0x4103c8,0xa01ef,40,22
U,0x4102f0,0x4103f0,0x80c7c,72,44
U,0x410338,0x410438,0x83c1b,24,8
U,0x410350,0x410450,0x83c1b,40,4
U,0x410378,0x410478,0xa1b0d,64,32
U,0x4103b8,0x4104b8,0x34f21,1040,1024
U,0x4107c8,0x4108c8,0x9f79d,40,9
U,0x4107f0,0x4108f0,0x9a079,192,172
U,0x4108b0,0x4109b0,0x9bf95,40,22
U,0x4108d8,0x4109d8,0x99f8f,224,208
U,0x4109b8,0x410ab8,0x9c46f,64,48
U,0x4109f8,0x410af8,0x9dfef,40,22
U,0x410a20,0x410b20,0x6e705,32,9
U,0x410a40,0x410b40,0xa01ef,56,22
U,0x410a78,0x410b78,0x7eab8,96,80
U,0x410ad8,0x410bd8,0x7eab8,96,80
U,0x410b38,0x410c38,0x28319,224,208
U,0x410c18,0x410d18,0x7eab8,96,80
U,0x410c78,0x410d78,0x285a9,2064,2048
U,0x411488,0x411588,0x285a9,112,92
U,0x4114f8,0x4115f8,0x80808,1120,1104
U,0x411958,0x411a58,0x803f4,4112,4096
U,0x412968,0x412a68,0x803f4,112,92
U,0x4129d8,0x412ad8,0x9d659,72,52
U,0x412a20,0x412b20,0x7e8ac,96,80
U,0x412a80,0x412b80,0x80808,1632,1616
U,0x4130e0,0x4131e0,0x803f4,2064,2048
U,0x4138f0,0x4139f0,0x803f4,112,92
U,0x413960,0x413a60,0x80808,256,240
U,0x413a60,0x413b60,0x803f4,1168,1152
U,0x413ef0,0x413ff0,0xa46c5,952,936
U,0x4142a8,0x4143a8,0xb1ff7,56,4
U,0x4142e0,0x4143e0,0x80808,176,160
U,0x414390,0x414490,0x803f4,4112,4096
U,0x4153a0,0x4154a0,0x803f4,112,92
U,0x415410,0x415510,0x7e8ac,96,80
U,0x415470,0x415570,0x803f4,112,92
U,0x4154e0,0x4155e0,0x80808,1296,1280
U,0x4159f0,0x415af0,0x803f4,112,92
U,0x415a60,0x415b60,0x7eab8,96,80
U,0x415ac0,0x415bc0,0x7e8ac,96,80
U,0x415b20,0x415c20,0x803f4,136,92
U,0x415ba8,0x415ca8,0x1405f,56,40
U,0x415be0,0x415ce0,0x1405f,56,40
U,0x415c18,0x415d18,0x13ed5,24,5
U,0x415c30,0x415d30,0x1405f,56,40
U,0x415c68,0x415d68,0x13ed5,24,8
U,0x415c80,0x415d80,0x1405f,56,40
U,0x415cb8,0x415db8,0x13ed5,24,7
U,0x415cd0,0x415dd0,0x1405f,56,40
U,0x415d08,0x415e08,0x13ed5,24,2
U,0x415d20,0x415e20,0x1405f,56,40
U,0x415d58,0x415e58,0x13ed5,24,7
U,0x415d70,0x415e70,0x1405f,56,40
U,0x415da8,0x415ea8,0x13ed5,32,12
U,0x415dc8,0x415ec8,0x1405f,56,40
U,0x415e00,0x415f00,0x13ed5,24,8
U,0x415e18,0x415f18,0x1405f,56,40
U,0x415e50,0x415f50,0x13ed5,32,11
U,0x415e70,0x415f70,0x13ed5,32,12
U,0x415e90,0x415f90,0x1405f,56,40
U,0x415ec8,0x415fc8,0x13ed5,32,13
U,0x415ee8,0x415fe8,0x13ed5,56,33
U,0x415f20,0x416020,0x1405f,56,40
U,0x415f58,0x416058,0x13ed5,32,11
U,0x415f78,0x416078,0x13ed5,24,8
U,0x415f90,0x416090,0x1405f,56,40
U,0x415fc8,0x4160c8,0x13ed5,24,7
U,0x415fe0,0x4160e0,0x1405f,56,40
U,0x416018,0x416118,0x13ed5,24,4
U,0x416030,0x416130,0x1405f,56,40
U,0x416068,0x416168,0x13ed5,24,2
U,0x416080,0x416180,0x13ed5,32,12
U,0x4160a0,0x4161a0,0x1405f,56,40
U,0x4160d8,0x4161d8,0x13ed5,24,2
U,0x4160f0,0x4161f0,0x13ed5,32,13
U,0x416110,0x416210,0x1405f,56,40
U,0x416148,0x416248,0x13ed5,24,4
U,0x416160,0x416260,0x1405f,56,40
U,0x416198,0x416298,0x13ed5,24,2
U,0x4161b0,0x4162b0,0x13ed5,32,12
U,0x4161d0,0x4162d0,0x1405f,56,40
U,0x416208,0x416308,0x13ed5,24,2
U,0x416220,0x416320,0x13ed5,32,13
U,0x416240,0x416340,0x1405f,56,40
U,0x416278,0x416378,0x13ed5,24,4
U,0x416290,0x416390,0x1405f,56,40
U,0x4162c8,0x4163c8,0x13ed5,24,2
U,0x4162e0,0x4163e0,0x1405f,56,40
U,0x416318,0x416418,0x13ed5,24,8
U,0x416330,0x416430,0x1405f,56,40
U,0x416368,0x416468,0x13ed5,32,11
U,0x416388,0x416488,0x13ed5,32,12
U,0x4163a8,0x4164a8,0x1405f,56,40
U,0x4163e0,0x4164e0,0x13ed5,32,13
U,0x416400,0x416500,0x13ed5,56,33
U,0x416438,0x416538,0x1405f,56,40
U,0x416470,0x416570,0x13ed5,32,11
U,0x416490,0x416590,0x13ed5,24,8
U,0x4164a8,0x4165a8,0x1405f,56,40
U,0x4164e0,0x4165e0,0x13ed5,24,7
U,0x4164f8,0x4165f8,0x1405f,56,40
U,0x416530,0x416630,0x13ed5,32,12
U,0x416550,0x416650,0x1405f,56,40
U,0x416588,0x416688,0x13ed5,24,7
U,0x4165a0,0x4166a0,0x1405f,56,40
U,0x4165d8,0x4166d8,0x13ed5,24,4
U,0x4165f0,0x4166f0,0x1405f,56,40
U,0x416628,0x416728,0x13ed5,24,2
U,0x416640,0x416740,0x13ed5,40,19
U,0x416668,0x416768,0x1405f,56,40
U,0x4166a0,0x4167a0,0x13ed5,24,2
U,0x4166b8,0x4167b8,0x13ed5,32,12
U,0x4166d8,0x4167d8,0x1405f,56,40
U,0x416710,0x416810,0x13ed5,24,4
U,0x416728,0x416828,0x1405f,56,40
U,0x416760,0x416860,0x13ed5,24,2
U,0x416778,0x416878,0x13ed5,40,19
U,0x4167a0,0x4168a0,0x1405f,56,40
U,0x4167d8,0x4168d8,0x13ed5,24,2
U,0x4167f0,0x4168f0,0x13ed5,32,12
U,0x416810,0x416910,0x1405f,56,40
U,0x416848,0x416948,0x13ed5,24,4
U,0x416860,0x416960,0x1405f,56,40
U,0x416898,0x416998,0x13ed5,24,2
U,0x4168b0,0x4169b0,0x1405f,56,40
U,0x4168e8,0x4169e8,0x13ed5,24,8
U,0x416900,0x416a00,0x1405f,56,40
U,0x416938,0x416a38,0x13ed5,32,11
U,0x416958,0x416a58,0x13ed5,32,12
U,0x416978,0x416a78,0x1405f,56,40
U,0x4169b0,0x416ab0,0x13ed5,32,13
U,0x4169d0,0x416ad0,0x13ed5,56,33
U,0x416a08,0x416b08,0x1405f,56,40
U,0x416a40,0x416b40,0x13ed5,32,11
U,0x416a60,0x416b60,0x13ed5,24,8
U,0x416a78,0x416b78,0x1405f,56,40
U,0x416ab0,0x416bb0,0x13ed5,24,7
U,0x416ac8,0x416bc8,0x1405f,56,40
U,0x416b00,0x416c00,0x13ed5,32,12
U,0x416b20,0x416c20,0x1405f,56,40
U,0x416b58,0x416c58,0x13ed5,24,7
U,0x416b70,0x416c70,0x1405f,56,40
U,0x416ba8,0x416ca8,0x13ed5,24,4
U,0x416bc0,0x416cc0,0x1405f,56,40
U,0x416bf8,0x416cf8,0x13ed5,24,2
U,0x416c10,0x416d10,0x13ed5,40,19
U,0x416c38,0x416d38,0x1405f,56,40
U,0x416c70,0x416d70,0x13ed5,24,2
U,0x416c88,0x416d88,0x13ed5,40,20
U,0x416cb0,0x416db0,0x1405f,56,40
U,0x416ce8,0x416de8,0x13ed5,24,4
U,0x416d00,0x416e00,0x1405f,56,40
U,0x416d38,0x416e38,0x13ed5,24,2
U,0x416d50,0x416e50,0x13ed5,40,19
U,0x416d78,0x416e78,0x1405f,56,40
U,0x416db0,0x416eb0,0x13ed5,24,2
U,0x416dc8,0x416ec8,0x13ed5,40,20
U,0x416df0,0x416ef0,0x1405f,56,40
U,0x416e28,0x416f28,0x13ed5,24,4
U,0x416e40,0x416f40,0x1405f,56,40
U,0x416e78,0x416f78,0x13ed5,24,2
U,0x416e90,0x416f90,0x1405f,56,40
U,0x416ec8,0x416fc8,0x13ed5,24,8
U,0x416ee0,0x416fe0,0x1405f,56,40
U,0x416f18,0x417018,0x13ed5,32,11
U,0x416f38,0x417038,0x13ed5,32,12
U,0x416f58,0x417058,0x1405f,56,40
U,0x416f90,0x417090,0x13ed5,32,13
U,0x416fb0,0x4170b0,0x13ed5,56,33
U,0x416fe8,0x4170e8,0x1405f,56,40
U,0x417020,0x417120,0x13ed5,32,11
U,0x417040,0x417140,0x13ed5,32,13
U,0x417060,0x417160,0x1405f,56,40
U,0x417098,0x417198,0x13ed5,24,7
U,0x4170b0,0x4171b0,0x1405f,56,40
U,0x4170e8,0x4171e8,0x13ed5,32,12
U,0x417108,0x417208,0x1405f,56,40
U,0x417140,0x417240,0x13ed5,24,7
U,0x417158,0x417258,0x1405f,56,40
U,0x417190,0x417290,0x13ed5,24,4
U,0x4171a8,0x4172a8,0x1405f,56,40
U,0x4171e0,0x4172e0,0x13ed5,24,2
U,0x4171f8,0x4172f8,0x13ed5,40,21
U,0x417220,0x417320,0x1405f,56,40
U,0x417258,0x417358,0x13ed5,24,2
U,0x417270,0x417370,0x13ed5,40,22
U,0x417298,0x417398,0x1405f,56,40
U,0x4172d0,0x4173d0,0x13ed5,24,4
U,0x4172e8,0x4173e8,0x1405f,56,40
U,0x417320,0x417420,0x13ed5,24,2
U,0x417338,0x417438,0x13ed5,40,21
U,0x417360,0x417460,0x1405f,56,40
U,0x417398,0x417498,0x13ed5,24,2
U,0x4173b0,0x4174b0,0x13ed5,40,22
U,0x4173d8,0x4174d8,0x1405f,56,40
U,0x417410,0x417510,0x13ed5,24,4
U,0x417428,0x417528,0x1405f,56,40
U,0x417460,0x417560,0x13ed5,24,2
U,0x417478,0x417578,0x1405f,56,40
U,0x4174b0,0x4175b0,0x13ed5,24,8
U,0x4174c8,0x4175c8,0x1405f,56,40
U,0x417500,0x417600,0x13ed5,32,11
U,0x417520,0x417620,0x13ed5,32,12
U,0x417540,0x417640,0x1405f,56,40
U,0x417578,0x417678,0x13ed5,32,13
U,0x417598,0x417698,0x13ed5,56,33
U,0x4175d0,0x4176d0,0x1405f,56,40
U,0x417608,0x417708,0x13ed5,32,11
U,0x417628,0x417728,0x13ed5,32,13
U,0x417648,0x417748,0x1405f,56,40
U,0x417680,0x417780,0x13ed5,24,7
U,0x417698,0x417798,0x1405f,56,40
U,0x4176d0,0x4177d0,0x13ed5,32,12
U,0x4176f0,0x4177f0,0x1405f,56,40
U,0x417728,0x417828,0x13ed5,24,7
U,0x417740,0x417840,0x1405f,56,40
U,0x417778,0x417878,0x13ed5,24,4
U,0x417790,0x417890,0x1405f,56,40
U,0x4177c8,0x4178c8,0x13ed5,24,2
U,0x4177e0,0x4178e0,0x13ed5,40,21
U,0x417808,0x417908,0x1405f,56,40
U,0x417840,0x417940,0x13ed5,24,2
U,0x417858,0x417958,0x13ed5,40,22
U,0x417880,0x417980,0x1405f,56,40
U,0x4178b8,0x4179b8,0x13ed5,24,4
U,0x4178d0,0x4179d0,0x1405f,56,40
U,0x417908,0x417a08,0x13ed5,24,2
U,0x417920,0x417a20,0x13ed5,40,21
U,0x417948,0x417a48,0x1405f,56,40
U,0x417980,0x417a80,0x13ed5,24,2
U,0x417998,0x417a98,0x13ed5,40,22
U,0x4179c0,0x417ac0,0x1405f,56,40
U,0x4179f8,0x417af8,0x13ed5,24,4
U,0x417a10,0x417b10,0x1405f,56,40
U,0x417a48,0x417b48,0x13ed5,24,8
U,0x417a60,0x417b60,0x1405f,56,40
U,0x417a98,0x417b98,0x1405f,56,40
U,0x417ad0,0x417bd0,0x13ed5,24,8
U,0x417ae8,0x417be8,0x1405f,56,40
U,0x417b20,0x417c20,0x13ed5,32,9
U,0x417b40,0x417c40,0x1405f,56,40
U,0x417b78,0x417c78,0x13ed5,32,9
U,0x417b98,0x417c98,0x1405f,56,40
U,0x417bd0,0x417cd0,0x13ed5,24,6
U,0x417be8,0x417ce8,0x1405f,56,40
U,0x417c20,0x417d20,0x1405f,56,40
U,0x417c58,0x417d58,0x13ed5,24,8
U,0x417c70,0x417d70,0x1405f,56,40
U,0x417ca8,0x417da8,0x13ed5,32,9
U,0x417cc8,0x417dc8,0x1405f,56,40
U,0x417d00,0x417e00,0x13ed5,32,9
U,0x417d20,0x417e20,0x1405f,56,40
U,0x417d58,0x417e58,0x13ed5,24,6
U,0x417d70,0x417e70,0x1405f,56,40
U,0x417da8,0x417ea8,0x1405f,56,40
U,0x417de0,0x417ee0,0x13ed5,24,8
U,0x417df8,0x417ef8,0x1405f,56,40
U,0x417e30,0x417f30,0x13ed5,32,9
U,0x417e50,0x417f50,0x1405f,56,40
U,0x417e88,0x417f88,0x13ed5,32,9
U,0x417ea8,0x417fa8,0x1405f,56,40
U,0x417ee0,0x417fe0,0x13ed5,24,6
U,0x417ef8,0x417ff8,0x1405f,56,40
U,0x417f30,0x418030,0x1405f,56,40
U,0x417f68,0x418068,0x13ed5,24,8
U,0x417f80,0x418080,0x1405f,56,40
U,0x417fb8,0x4180b8,0x13ed5,32,9
U,0x417fd8,0x4180d8,0x1405f,56,40
U,0x418010,0x418110,0x13ed5,32,9
U,0x418030,0x418130,0x1405f,56,40
U,0x418068,0x418168,0x13ed5,24,6
U,0x418080,0x418180,0x1405f,56,40
U,0x4180b8,0x4181b8,0x1405f,56,40
U,0x4180f0,0x4181f0,0x13ed5,24,8
U,0x418108,0x418208,0x1405f,56,40
U,0x418140,0x418240,0x13ed5,32,9
U,0x418160,0x418260,0x1405f,56,40
U,0x418198,0x418298,0x13ed5,32,9
F,0x4181b8,0x4182b8,0x812b7,80,20
U,0x418208,0x418308,0x1405f,56,40
U,0x418240,0x418340,0x13ed5,32,10
U,0x418260,0x418360,0x1405f,56,40
U,0x418298,0x418398,0x13ed5,24,2
U,0x4182b0,0x4183b0,0x1405f,56,40
U,0x4182e8,0x4183e8,0x13ed5,32,9
U,0x418308,0x418408,0x1405f,56,40
U,0x418340,0x418440,0x13ed5,24,5
U,0x418358,0x418458,0x1405f,56,40
U,0x418390,0x418490,0x13ed5,24,8
U,0x4183a8,0x4184a8,0x1405f,56,40
U,0x4183e0,0x4184e0,0x13ed5,24,5
U,0x4183f8,0x4184f8,0x1405f,56,40
U,0x418430,0x418530,0x13ed5,24,5
U,0x418448,0x418548,0x13ed5,24,1
U,0x418460,0x418560,0x1405f,56,40
U,0x418498,0x418598,0x13ed5,24,7
U,0x4184b0,0x4185b0,0x1405f,56,40
U,0x4184e8,0x4185e8,0x13ed5,24,2
U,0x418500,0x418600,0x1405f,56,40
U,0x418538,0x418638,0x13ed5,32,9
U,0x418558,0x418658,0x1405f,56,40
U,0x418590,0x418690,0x13ed5,24,5
U,0x4185a8,0x4186a8,0x1405f,56,40
U,0x4185e0,0x4186e0,0x13ed5,24,8
U,0x4185f8,0x4186f8,0x1405f,56,40
U,0x418630,0x418730,0x13ed5,24,5
U,0x418648,0x418748,0x1405f,56,40
U,0x418680,0x418780,0x13ed5,24,5
U,0x418698,0x418798,0x13ed5,24,1
U,0x4186b0,0x4187b0,0x1405f,56,40
U,0x4186e8,0x4187e8,0x13ed5,24,7
U,0x418700,0x418800,0x1405f,56,40
U,0x418738,0x418838,0x13ed5,24,2
U,0x418750,0x418850,0x1405f,56,40
U,0x418788,0x418888,0x13ed5,32,9
U,0x4187a8,0x4188a8,0x1405f,56,40
U,0x4187e0,0x4188e0,0x13ed5,24,5
U,0x4187f8,0x4188f8,0x1405f,56,40
U,0x418830,0x418930,0x13ed5,24,8
U,0x418848,0x418948,0x1405f,56,40
U,0x418880,0x418980,0x13ed5,24,5
U,0x418898,0x418998,0x1405f,56,40
U,0x4188d0,0x4189d0,0x13ed5,24,5
U,0x4188e8,0x4189e8,0x13ed5,24,1
U,0x418900,0x418a00,0x1405f,56,40
U,0x418938,0x418a38,0x13ed5,24,7
U,0x418950,0x418a50,0x3dc13,2720,2704
U,0x4193f0,0x4194f0,0x803f4,3088,3072
U,0x41a000,0x41a100,0x803f4,3088,3072
U,0x41ac10,0x41ad10,0x80808,896,880
U,0x41af90,0x41b090,0x803f4,1040,1024
U,0x41b3a0,0x41b4a0,0x803f4,12304,12288
U,0x41e3b0,0x41e4b0,0x803f4,112,92
U,0x41e420,0x41e520,0x80808,1296,1280
U,0x41e930,0x41ea30,0x803f4,5136,5120
U,0x41fd40,0x41fe40,0x803f4,112,92
U,0x41fdb0,0x41feb0,0x803f4,4112,4096
U,0x420dc0,0x420ec0,0x803f4,112,92
F,0x420e30,0x420f30,0x956db,64,36
U,0x420e70,0x420f70,0x42d97,40,20
U,0x420e98,0x420f98,0x7eab8,96,80
U,0x420ef8,0x420ff8,0x42d97,40,20
U,0x420f20,0x421020,0x7eab8,96,80
U,0x420f80,0x421080,0x42d97,40,20
U,0x420fa8,0x4210a8,0x7eab8,96,80
U,0x421008,0x421108,0x42d97,40,20
U,0x421030,0x421130,0x7eab8,96,80
U,0x421090,0x421190,0x42d97,40,20
U,0x4210b8,0x4211b8,0x7eab8,96,80
U,0x421118,0x421218,0x42d97,40,20
U,0x421140,0x421240,0x7eab8,96,80
U,0x4211a0,0x4212a0,0x7eab8,96,80
U,0x421200,0x421300,0x80c7c,64,44
U,0x421240,0x421340,0x7e8ac,96,80
U,0x4212a0,0x4213a0,0x7eab8,96,80
U,0x421300,0x421400,0x7e8ac,96,80
U,0x421360,0x421460,0x7e8ac,96,80
U,0x4213c0,0x4214c0,0x7e8ac,96,80
U,0x421420,0x421520,0x803f4,1040,1024
U,0x421830,0x421930,0x803f4,112,92
U,0x4218a0,0x4219a0,0x803f4,1040,1024
U,0x421cb0,0x421db0,0x803f4,112,92
U,0x421d20,0x421e20,0x7e8ac,96,80
U,0x421d80,0x421e80,0x7eab8,96,80
U,0x421de0,0x421ee0,0x961bb,24,4
U,0x421df8,0x421ef8,0x97b51,376,360
U,0x421f70,0x422070,0x6e705,32,11
U,0x421f90,0x422090,0x9642b,328,312
U,0x4220d8,0x4221d8,0x96435,472,456
U,0x4222b0,0x4223b0,0x96455,24,4
U,0x4222c8,0x4223c8,0x6e705,32,9
U,0x4222e8,0x4223e8,0x97b9d,24,4
U,0x422300,0x422400,0x97aa1,288,268
U,0x422420,0x422520,0x97e8b,24,4
U,0x422438,0x422538,0xa4c29,24,4
U,0x422450,0x422550,0x9ec37,88,72
U,0x4224a8,0x4225a8,0x95a9f,48,28
U,0x4224d8,0x4225d8,0x95a9f,48,28
U,0x422508,0x422608,0x9ef85,56,40
U,0x422540,0x422640,0x95a9f,48,28
F,0x422570,0x422670,0x363c5,32,8
U,0x422590,0x422690,0xaf3ed,48,12
U,0x4225c0,0x4226c0,0x9d865,72,56
U,0x422608,0x422708,0x9d88b,1472,1456
U,0x422bc8,0x422cc8,0x9d893,64,48
U,0x422c08,0x422d08,0x986b3,40,20
U,0x422c30,0x422d30,0x986e7,112,96
U,0x422ca0,0x422da0,0x96559,104,88
U,0x422d08,0x422e08,0xb1e05,360,342
U,0x422e70,0x422f70,0x83c1b,48,26
F,0x422ea0,0x422fa0,0x9594d,256,88
U,0x422fa0,0x4230a0,0x9fe83,96,80
F,0x423000,0x423100,0x7e8ac,176,80
U,0x4230b0,0x4231b0,0x83c1b,24,1
U,0x4230c8,0x4231c8,0x83c1b,40,20
F,0x4230f0,0x4231f0,0x812b7,40,20
U,0x423118,0x423218,0xb25ff,496,476
U,0x423308,0x423408,0x9e865,88,72
U,0x423360,0x423460,0x95a9f,48,28
U,0x423390,0x423490,0x95a9f,48,28
U,0x4233c0,0x4234c0,0xa4883,56,40
U,0x4233f8,0x4234f8,0xa350b,112,96
U,0x423468,0x423568,0xb0193,1048,1028
U,0x423880,0x423980,0xaf9f7,40,20
U,0x4238a8,0x4239a8,0x9d865,72,56
U,0x4238f0,0x4239f0,0x9d88b,1472,1456
U,0x423eb0,0x423fb0,0x9d893,64,48
U,0x423ef0,0x423ff0,0x9ef85,56,40
U,0x423f28,0x424028,0x95a9f,48,28
U,0x423f58,0x424058,0x9fa4f,64,48
U,0x423f98,0x424098,0x9f79d,32,9
U,0x423fb8,0x4240b8,0x6e705,32,9
U,0x423fd8,0x4240d8,0xb1fa5,144,128
F,0x424068,0x424168,0x9e9a1,3200,512
U,0x424ce8,0x424de8,0x803f4,2064,2048
U,0x4254f8,0x4255f8,0x803f4,112,92
F,0x425568,0x425668,0x9e083,32,12
U,0x425588,0x425688,0x803f4,2064,2048
U,0x425d98,0x425e98,0x803f4,112,92
U,0x425e08,0x425f08,0x140f3,32,6
U,0x425e28,0x425f28,0x803f4,2064,2048
U,0x426638,0x426738,0x803f4,112,92
F,0x4266a8,0x4267a8,0x14d11,39240,1932

对比之下,比较明显地增加了几条新 heap 使用信息

1
2
3
U,0x425e08,0x425f08,0x140f3,32,6
U,0x425e28,0x425f28,0x803f4,2064,2048
U,0x426638,0x426738,0x803f4,112,92

再用 address2line 工具定位这几块内存是哪里申请的

1
2
3
4
5
6
7
8
toolchain/gcc-arm-none-eabi-5_4-2016q3/bin 
❯ ./arm-none-eabi-addr2line -e ~/FC41D/beken_freertos_sdk_release-SDK_3.0.21/out/beken7231_bsp.elf -f 0x140f3 0x803f4 0x803f4
cJSON_strdup
/home/x/FC41D/beken_freertos_sdk_release-SDK_3.0.21/demos/common/json/cJSON.c:67
rtos_create_thread
/home/x/FC41D/beken_freertos_sdk_release-SDK_3.0.21/beken378/os/FreeRTOSv9.0.0/rtos_pub.c:98
rtos_create_thread
/home/x/FC41D/beken_freertos_sdk_release-SDK_3.0.21/beken378/os/FreeRTOSv9.0.0/rtos_pub.c:98

/home/x/FC41D/beken_freertos_sdk_release-SDK_3.0.21/beken378/os/FreeRTOSv9.0.0/rtos_pub.c:98 对应的是创建线程的函数 rtos_create_thread

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
int ali_iot_close(custom_func_ch_id_e func_id, void *hdl)
{
    ali_iot_mqtt_client_t *mqtt_client = hdl;

    if (mqtt_client == NULL)
    {
        return -1;
    }
    rtos_lock_mutex(&mqtt_client->lock);

    rtos_delete_thread(mqtt_client->task);
    MQTTDisconnect(&mqtt_client->client);
	NetworkDisconnect(&mqtt_client->network);
    mqtt_client->ev_cb(mqtt_client, QL_MQTT_CLOSE, (QL_MQTT_OK << 16)|QL_MQTT_CLOSE_BY_DISCONNECT, NULL, (void *)mqtt_client->func_id);
    if(mqtt_client->sign_mqtt)
    {
        free(mqtt_client->sign_mqtt);
    }
    if(mqtt_client->sub_topic[0])
    {
        free(mqtt_client->sub_topic[0]);
    }
    if(mqtt_client->sub_topic[1])
    {
        free(mqtt_client->sub_topic[1]);
    }
    rtos_unlock_mutex(&mqtt_client->lock);

    rtos_deinit_mutex(&mqtt_client->lock);
    free(mqtt_client);

    return 0;
}

分析代码之后,找到原因是关闭mqtt的时候,没有正确删除线程导致的内存泄漏。 rtos_delete_thread(mqtt_client->task); 传参不对,修改为 rtos_delete_thread(&mqtt_client->task);之后正常。

案例2

挂测日志,出现 malloc 失败,主动重启:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
[2024-07-26 10:23:39]  malloc failed !!!!!!!!!
[2024-07-26 10:23:39]  
[2024-07-26 10:23:39]  address: 0x40aaa0
[2024-07-26 10:23:39]  size: 152928
[2024-07-26 10:23:39]  avail: 352
[2024-07-26 10:23:39]  pool_start: 0x40aaa0
[2024-07-26 10:23:39]  pool_end: 0x42fff0
[2024-07-26 10:23:39]  state,block_addr,user_addr,caller,blocksize,wanted_size
[2024-07-26 10:23:39]  U,0x40aaa0,0x40aab0,0x1b959,4120,4096
[2024-07-26 10:23:39]  U,0x40bab8,0x40bac8,0x1b979,40,20
[2024-07-26 10:23:39]  U,0x40bae0,0x40baf0,0x1b959,536,512
[2024-07-26 10:23:39]  U,0x40bcf8,0x40bd08,0x1b979,40,20
[2024-07-26 10:23:39]  U,0x40bd20,0x40bd30,0x1b959,4120,4096
[2024-07-26 10:23:39]  U,0x40cd38,0x40cd48,0x1b979,40,20
[2024-07-26 10:23:39]  U,0x40cd60,0x40cd70,0x1b959,536,512
[2024-07-26 10:23:39]  U,0x40cf78,0x40cf88,0x1b979,40,20
[2024-07-26 10:23:39]  U,0x40cfa0,0x40cfb0,0x7e750,104,80
[2024-07-26 10:23:39]  U,0x40d008,0x40d018,0x7e544,104,80

......

[2024-07-26 10:23:41]  U,0x42f368,0x42f378,0x7e750,104,80
[2024-07-26 10:23:41]  U,0x42f3d0,0x42f3e0,0x7e750,104,80
[2024-07-26 10:23:41]  U,0x42f438,0x42f448,0x7e750,104,80
[2024-07-26 10:23:41]  U,0x42f4a0,0x42f4b0,0x7e750,104,80
[2024-07-26 10:23:41]  U,0x42f508,0x42f518,0x7e750,104,80
[2024-07-26 10:23:41]  U,0x42f570,0x42f580,0x7e750,104,80
[2024-07-26 10:23:41]  U,0x42f5d8,0x42f5e8,0x7e750,104,80
[2024-07-26 10:23:41]  U,0x42f640,0x42f650,0x7e750,104,80
[2024-07-26 10:23:41]  U,0x42f6a8,0x42f6b8,0x7e750,104,80
[2024-07-26 10:23:41]  U,0x42f710,0x42f720,0x4ae8b,416,396
[2024-07-26 10:23:41]  U,0x42f8b0,0x42f8c0,0x7e750,104,80
[2024-07-26 10:23:41]  U,0x42f918,0x42f928,0x7e750,104,80
[2024-07-26 10:23:41]  U,0x42f980,0x42f990,0x28721,104,80
[2024-07-26 10:23:41]  F,0x42f9e8,0x42f9f8,0x95719,112,88
[2024-07-26 10:23:41]  U,0x42fa58,0x42fa68,0x9e76d,536,512
[2024-07-26 10:23:41]  U,0x42fc70,0x42fc80,0xacb8d,792,768
[2024-07-26 10:23:41]  F,0x42ff88,0x42ff98,(nil),104,0
[2024-07-26 10:23:41]  bk_reboot
[2024-07-26 10:23:41]  wdt reboot

写脚本,将 log 保存为 csv 文件,并把 caller 地址对应的函数名找出来

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
from elftools.elf.elffile import ELFFile
import csv

def find_function_name(elf_file, address):
    symtab = elf_file.get_section_by_name('.symtab')
    if not symtab:
        print("No symbol table found in the ELF file.")
        return None
    
    for symbol in symtab.iter_symbols():
        start_addr = symbol.entry.st_value
        size = symbol.entry.st_size
        if start_addr <= address < start_addr + size:
            return symbol.name
    
    print(f"No function found at address 0x{address:x} in the ELF file.")
    return None

def find_function_address(elf_file, function_name):
    symtab = elf_file.get_section_by_name('.symtab')
    if not symtab:
        print("No symbol table found in the ELF file.")
        return None
    
    for symbol in symtab.iter_symbols():
        if symbol.name == function_name:
            return symbol.entry.st_value
    
    print(f"Function '{function_name}' not found in the ELF file.")
    return None


def read_csv(file_path):
    with open(file_path, mode='r', newline='', encoding='utf-8') as csv_file:
        csv_reader = csv.reader(csv_file)
        header = next(csv_reader)  # 读取表头
        data = [row for row in csv_reader]  # 读取数据
    return header, data

def write_csv(file_path, header, data):
    with open(file_path, mode='w', newline='', encoding='utf-8') as csv_file:
        csv_reader = csv.writer(csv_file)
        csv_reader.writerow(header)
        csv_reader.writerows(data)
        

f = open("malloc failed/beken7231_bsp.elf", "rb")
elffile = ELFFile(f)
header, data = read_csv("malloc failed/heap.csv")
f.close()

header.append("func_name")

for row in data:
    caller = row[3]
    try:
        # 尝试将十六进制字符串转换为整数
        caller = int(caller, 16)
        fn = find_function_name(elffile, caller)
    except ValueError:
        fn = None
    except TypeError:
        fn = None
    
    # print(caller)
    
    
    if fn is None:
        fn = ""
        # caller = hex(caller)
    row.append(fn)
    # print((caller, fn))

# 将使用中的内存过滤出来
data2 =[]
for i in data:
    if i[0] == "U":
        data2.append(i)
        


write_csv("malloc failed/heap_U.csv", header, data2)

处理之后的部分数据

stateblock_addruser_addrcallerblocksizewanted_sizefunc_name
U0x40aaa00x40aab00x1b95941204096kfifo_alloc
U0x40bab80x40bac80x1b9794020kfifo_alloc
U0x40bae00x40baf00x1b959536512kfifo_alloc
U0x40bcf80x40bd080x1b9794020kfifo_alloc
U0x40bd200x40bd300x1b95941204096kfifo_alloc
U0x40cd380x40cd480x1b9794020kfifo_alloc
U0x40cd600x40cd700x1b959536512kfifo_alloc
U0x40cf780x40cf880x1b9794020kfifo_alloc
U0x40cfa00x40cfb00x7e75010480xQueueCreateMutex
U0x40d0080x40d0180x7e54410480xQueueCreateCountingSemaphore
U0x40d0700x40d0800x2872110480sys_sem_new
U0x40d0d80x40d0e80x140c36440cJSON_New_Item
U0x40d1180x40d1280x839e7568mm_printf_beacon_ie
U0x40d1500x40d1600x9f569329dup_binstr
U0x40d1700x40d1800x9ffbb4022os_memdup
U0x40d1980x40d1a80x7111d409os_strdup
U0x40d1c00x40d1d00x839e76426mm_printf_beacon_ie
U0x40d2000x40d2100x3587110481024dhcp_server_init
U0x40d6180x40d6280x285f911292sys_mbox_new
U0x40d6880x40d6980x99e45192172wpa_init
U0x40d7480x40d7580x9bd614022wpa_auth_gen_wpa_ie
U0x40d7700x40d7800x99d5b232208wpa_group_init
U0x40d8580x40d8680x9c23b7248pmksa_cache_auth_init
U0x40d8a00x40d8b00x9ddbb4022hostap_set_generic_elem
U0x40d8c80x40d8d80x9ffbb4822os_memdup

统计函数名字出现的频次,进行分组。

func_name计数项:func_name
add_notifier1
ali_iot_open2
atsvr_msg_main1
cfg_param_init3
cJSON_New_Item99
cJSON_strdup120
cli_init1
dhcp_server_init1
dup_binstr2
eloop_register_signal1
eloop_register_sock1
eloop_register_timeout1
fsocket_init6
fsocket_send1
handle_probe_req1
handle_read1
hostap_get_hw_feature_data6
hostap_init1
hostap_send_mlme1
hostap_set_generic_elem1
hostapd_add_iface1
hostapd_alloc_bss_data1
hostapd_alloc_iface1
hostapd_config_defaults3
hostapd_init1
hostapd_main_entry1
hostapd_prepare_rates2
hostapd_setup_wpa_psk1
kfifo_alloc8
l2_packet_init2
mm_printf_beacon_ie5
os_memdup2
os_realloc_array1
os_strdup4
parse_string10
pmksa_cache_auth_init1
pmksa_cache_init1
prvCheckForValidListAndQueue1
ql_ssl_ctx_init6
rtos_create_thread28
rtos_init_queue8
rtos_init_timer2
supplicant_main_entry1
sys_mbox_new4
sys_sem_new5
sys_thread_new2
vTaskStartScheduler2
wpa_auth_gen_wpa_ie1
wpa_bss_update_scan_res2
wpa_config_alloc_empty1
wpa_config_read1
wpa_driver_init1
wpa_group_init1
wpa_init1
wpa_psk_cache_init1
wpa_sm_init1
wpa_supplicant_add_iface2
wpa_supplicant_init2
wpa_supplicant_init_wpa1
xQueueCreateCountingSemaphore10
xQueueCreateMutex428
xTimerCreateTimerTask2

xQueueCreateMutex 出现的次数最多,xQueueCreateMutex 调用一次分配 104 内存,出现 428 次,也就使用了 40 多 k 的内存一直没释放。

排查代码逻辑,在联网失败的时候进入错误处理,有个互斥锁创建了未销毁,导致内存泄漏。

小结

内存泄漏的判断方法:

  1. 功能打开关闭之后,对比前后的 heap info 信息,看看有哪些新增加的内存分配信息,按照这个线索去排查。
  2. 挂机压测一段时间之后,打印 heap info 信息,按照 caller 出现的次数排序,出现次数较多的前几个 caller,或者内存申请较多的caller,是该怀疑存在内存泄漏的对象。

heap 内存写越界案例

free 的时候检测到内存块被破坏

1
2
3
4
5
mem corrupt,block:0x422ef8, blocksize:24, xWantedSize:4, caller:0x34747
dump block:
00000000:  00 00 00 00 18 00 00 00  ........
00000008:  04 00 00 00 47 47 03 00  ....GG..
00000010:  48 54 54 50 2F 31 2E 30  HTTP/1.0

调用者申请了4字节内存空间,分配的内存块大小是24字节,减去头部16字节,后面填充了4字节的0xfd,从dump的内存数据来看,填充的数据都被覆盖完了, 通过 caller:0x34747 查找代码位置

1
2
3
4
FC41D/beken_freertos_sdk_release-SDK_3.0.21 on  Iotbranch [!?⇡] 
❯ ./toolchain/gcc-arm-none-eabi-5_4-2016q3/bin/arm-none-eabi-addr2line -e Release/Debug/beken7231_bsp.elf  -f 0x34747
fs_open_custom
/home/x/FC41D/beken_freertos_sdk_release-SDK_3.0.21/beken378/func/lwip_intf/lwip-2.0.2/src/apps/httpd/custom_fsdata.c:239

对应代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
int fs_open_custom(struct fs_file *file, const char *name)
{
    char *wifi_data="{\"aps\":[{\"ssid\":\"123\"},{\"ssid\":\"test234\"}]}";
    int file_data_len = 0;
    
     /* this example only provides one file */
     if (!strcmp(name, "/wifilist.html"))
     {
         /* initialize fs_file correctly */
         memset(file, 0, sizeof(struct fs_file));
         file_data_len = strlen((char *)CUSTOM_FSDATA_WIFILIST_HTML_HEADER) + strlen(wifi_data) +2;
         file->pextension = malloc(sizeof(file_data_len));
         if (file->pextension != NULL)
         {
            memset(file->pextension, 0, file_data_len);
            file_data_len = snprintf(file->pextension, file_data_len - 1, "%s%s", (char *)CUSTOM_FSDATA_WIFILIST_HTML_HEADER, wifi_data);
        
            file->data = (const char *)file->pextension;
            file->len = file_data_len; /* don't send the trailing 0 */
            file->index = file->len;
            /* allow persisteng connections */
            file->flags = FS_FILE_FLAGS_HEADER_INCLUDED;
            return 1;
         }
     }
     else if(!strcmp(name, "/index.html"))
     {
         char *sta_state_data = NULL;
         uint32 uart_band = 9600;
         uint8 ssid[33] = {0};
         uint8 psk[64] = {0};

         int apon = 0;
         char *ap_state_data = NULL;

         if (custom_fsdata_sta_state() == 1)
         {
             sta_state_data = CUSTOM_FSDATA_STA_CONNECTED;
         }
         else
         {
             sta_state_data = CUSTOM_FSDATA_STA_DISCONNECTED;
         }

         custom_sw_ap_cfg_get(apssid, appass, &apon);

         if (apon == 1)
         {
             ap_state_data = "Up";
         }
         else
         {
             ap_state_data = "Down";
         }

         custom_config_uart_braud_get(&uart_band);

         custom_sta_cfg_get(ssid, psk);
         /* initialize fs_file correctly */
         memset(file, 0, sizeof(struct fs_file));
         file_data_len = strlen((char *)CUSTOM_FSDATA_INDEX_HTML_HEADER) + strlen((char *)CUSTOM_FSDATA_INDEX_HTML_FILE_FMT) + 10 /* for uart band */ + strlen((char *)ssid) + strlen(ap_state_data) + strlen(sta_state_data) + strlen((char *)apssid) + 1 /* \0 */;
         file->pextension = malloc(sizeof(file_data_len));
         if (file->pextension != NULL)
         {
            memset(file->pextension, 0, file_data_len);
            file_data_len = snprintf(file->pextension, file_data_len - 1, (char *)CUSTOM_FSDATA_INDEX_HTML_FILE_FMT, (char *)CUSTOM_FSDATA_INDEX_HTML_HEADER, (char *)ssid, sta_state_data, (char *)apssid, ap_state_data, uart_band);
        
            file->data = (const char *)file->pextension;
            file->len = file_data_len; /* don't send the trailing 0 */
            file->index = file->len;
            /* allow persisteng connections */
            file->flags = FS_FILE_FLAGS_HEADER_INCLUDED;
            return 1;
         }
     }
     return 0;
}

file->pextension = malloc(sizeof(file_data_len)); 传的参数传错了,sizeof(file_data_len) 是4字节,实际需要申请 file_data_len 字节,导致后面内存写越界了。