malloc及free使用注意事项

1. 时间不确定性

  malloc的实现很简单,它首先会扫描之前由free()所释放的空闲内存块列表,以求找到尺寸大于或等于要求的一块空闲内存。如果这一内存块的尺寸正好与要求相当,就将它返回给调用者,如果是一块较大的内存,那么将对其进行分割,在将一块大小相当的内存返回给调用者的同时,把较小的那块空闲内存块保留在空闲列表中。由于malloc算法的实现特性,malloc不具有确定性(每次调用执行的时间可能会不同),在高实时性要求的场合中需要充分考虑到这一点。比如不建议在中断中调用malloc。

 

2. 线程不一定安全

  按照我个人的理解,在linux或windows系统中,如果使用-pthread进行编译,malloc将成为线程安全的。但在ANSI C中malloc是不可重入的,也就是非线程安全。对于我们这些苦逼的嵌入式程序员来说,这就意味着在keil、IAR等编译器中使用的malloc是非线程安全的,需要自行加锁,以保证线程安全。以在FreeRTOS中内存管理中,方法3(heap_3.c)是对malloc进行了封装,实现线程安全功能。

 1 void *pvPortMalloc( size_t xWantedSize )
 2 {
 3     void *pvReturn;
 4 
 5     vTaskSuspendAll();
 6     {
 7         pvReturn = malloc( xWantedSize );
 8         traceMALLOC( pvReturn, xWantedSize );
 9     }
10     ( void ) xTaskResumeAll();
11 
12     #if( configUSE_MALLOC_FAILED_HOOK == 1 )
13     {
14         if( pvReturn == NULL )
15         {
16             extern void vApplicationMallocFailedHook( void );
17             vApplicationMallocFailedHook();
18         }
19     }
20     #endif
21 
22     return pvReturn;
23 }
24 /*-----------------------------------------------------------*/
25 
26 void vPortFree( void *pv )
27 {
28     if( pv )
29     {
30         vTaskSuspendAll();
31         {
32             free( pv );
33             traceFREE( pv, 0 );
34         }
35         ( void ) xTaskResumeAll();
36     }
37 }

 3. malloc不一定成功

     当内存碎片化,导致剩余最大块的内存都不足以分配时,此时malloc返回NULL,一般的,我们需要对malloc的返回值进行判断。

1 uint32_t *p;
2 p = malloc(100);
3 if (p ==NULL)
4 {
5     printf("申请内存失败\r\n");
6     //do something      
7 }

4. malloc和free必须成对出现

    为了避免内存泄漏,malloc与free必须成对出现,下面代码展示了malloc与free貌似成对出现,其实没有free的现象。

 1 void malloc_free_test1(void)
 2 {
 3     uint32_t p;
 4 
 5     p = malloc(100);
 6     if (NULL == p)
 7     {
 8         return;  
 9     }
10 
11     if (xxx)
12     {
13         free(p); //此处释放后,return离开
14         return;
15     }
16 
17     //此时xxx条件不成立,却return离开,没有free,造成内存泄漏
18     return;
19 }

5. 给野指针加一根缰绳

    · free一片内存,只是把这一片内存对应的链表删除,内存内容实际还是存在的,

    · free之后对应的指针不为NULL,很多地方只会判断指针是否为NULL,而实际内存已释放,可能已经被分配给其他人,导致意想不到的的后果。

    · 所以free之后请把指针置为NULL。

 1 void malloc_free_test2(void)
 2 {
 3     uint32_t *p;
 4 
 5     p = malloc(100);
 6     if(NULL == p)
 7     {
 8         return;
 9     }
10 
11     //错误的做法
12     free(p);
13     if (NULL != p) //此时p不等与NULL,防御编程不起作用
14     {
15         *p = 0x123456;//已经free,此时对p的任何操作都存在危险
16     }
17     
18 
19     //正确的做法
20     free(p);
21     p = NULL;
22     if (NULL != p)//p已经为NULL,此时防御编程起作用
23     {
24         *p = 0x123456;
25     }
26 }

 

posted @ 2020-10-27 23:25  摩羯兔有点冷  阅读(1054)  评论(0编辑  收藏  举报