gliethttp 发表于 2007-9-30 10:34

浅析FreeRTOS_v4.5.0内存分配与回收及其改进方案

浅析FreeRTOS_v4.5.0内存分配与回收函数及其改进方案---pvPortMalloc()和vPortFree()<br /><br />**来源:http://gliethttp.cublog.cn<br /><br />[注:以下为FreeRTOS_v4.5.0在at91sam7s64处理器上的动态内存分配、释放函数(gliethtp)]<br />&nbsp;&nbsp;FreeRTOS_v4.5.0一共提供3中动态内存分配和回收机制,可以通过具体需要任意选择其中一种,<br />第1种:只是提供堆数组上地址的线性分配,不提供内存回收;<br />第2种:提供堆数组上地址的线性分配和回收,但是回收过程不能将小内存合并成大内存<br />第3种:使用编译器自带的malloc和free函数<br />以上不论哪一种方式都是对堆数组xHeap进行操作,其定义如下:<br />static&nbsp;struct&nbsp;xRTOS_HEAP<br />{<br />//ulDummy仅仅用来告诉编译器分配的configTOTAL_HEAP_SIZE个字节连续空间的起始地址是4字节对齐的<br />&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;portLONG&nbsp;ulDummy;<br />&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;portCHAR&nbsp;ucHeap[&nbsp;configTOTAL_HEAP_SIZE&nbsp;];<br />}&nbsp;xHeap;<br />//------------------------------------------------------------------------------<br />&lt1.1&gt第1种内存动态分配<br />void&nbsp;*pvPortMalloc(&nbsp;size_t&nbsp;xWantedSize&nbsp;)<br />{<br />void&nbsp;*pvReturn&nbsp;=&nbsp;NULL;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;#if&nbsp;portBYTE_ALIGNMENT&nbsp;!=&nbsp;1<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;xWantedSize&nbsp;&&nbsp;heapBYTE_ALIGNMENT_MASK&nbsp;)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//字节对齐,at91sam7s64默认使用4字节对齐<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//所以下面折行程序,将xWantedSize扩展成4字节的倍数,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//比如:xWantedSize=13,那么xWantedSize=13+(4-13%4)=13+3=16(gliethttp)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xWantedSize&nbsp;+=&nbsp;(&nbsp;portBYTE_ALIGNMENT&nbsp;-&nbsp;(&nbsp;xWantedSize&nbsp;&&nbsp;heapBYTE_ALIGNMENT_MASK&nbsp;)&nbsp;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;#endif<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;vTaskSuspendAll();//锁住调度器<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;(&nbsp;(&nbsp;xNextFreeByte&nbsp;+&nbsp;xWantedSize&nbsp;)&nbsp;&lt&nbsp;configTOTAL_HEAP_SIZE&nbsp;)&nbsp;&&<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&nbsp;(&nbsp;xNextFreeByte&nbsp;+&nbsp;xWantedSize&nbsp;)&nbsp;&gt&nbsp;xNextFreeByte&nbsp;)&nbsp;&nbsp;&nbsp;&nbsp;)//防止申请数据空间超出4字节范围,过大溢出<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//还有足够的空间,那么把申请到的空间首地址作为返回地址<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pvReturn&nbsp;=&nbsp;&(&nbsp;xHeap.ucHeap[&nbsp;xNextFreeByte&nbsp;]&nbsp;);//取得堆数组中xNextFreeByte偏移处的地址值<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xNextFreeByte&nbsp;+=&nbsp;xWantedSize;//调整xNextFreeByte,为下一次分配空间做准备<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />//调度器解锁,此间会有若干处理,详细细节可以参见《浅析FreeRTOS_v4.5.0延时机制---vTaskDelay()的实现》<br />//**地址:http://blog.chinaunix.net/u1/38994/showart_392389.html<br />&nbsp;&nbsp;&nbsp;&nbsp;xTaskResumeAll();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;pvReturn;//将申请到的内存块起始地址返回<br />}<br />&lt1.2&gt第1种动态内存回收<br />void&nbsp;vPortFree(&nbsp;void&nbsp;*pv&nbsp;)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;(&nbsp;void&nbsp;)&nbsp;pv;//第1种方式不提供内存回收机制<br />}<br />//------------------------------------------------------------------------------<br />&lt2.1&gt第2种内存动态分配<br />void&nbsp;*pvPortMalloc(&nbsp;size_t&nbsp;xWantedSize&nbsp;)<br />{<br />xBlockLink&nbsp;*pxBlock,&nbsp;*pxPreviousBlock,&nbsp;*pxNewBlockLink;<br />static&nbsp;portBASE_TYPE&nbsp;xHeapHasBeenInitialised&nbsp;=&nbsp;pdFALSE;//标志是否首次使用pvPortMalloc()<br />void&nbsp;*pvReturn&nbsp;=&nbsp;NULL;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;vTaskSuspendAll();//锁住调度器<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;xHeapHasBeenInitialised&nbsp;==&nbsp;pdFALSE&nbsp;)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//第1次调用pvPortMalloc(),那么需要初始化一些关键量,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//主要是在xStart和xEnd之间将xHeap.ucHeap插进去,下面是一个简单的单向链接图示<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//xStart-&gtxHeap.ucHeap-&gtxEnd-&gtNULL<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;prvHeapInit();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xHeapHasBeenInitialised&nbsp;=&nbsp;pdTRUE;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;xWantedSize&nbsp;&gt&nbsp;0&nbsp;)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />//对heapSTRUCT_SIZE的定义是这样的:<br />//static&nbsp;const&nbsp;unsigned&nbsp;portSHORT&nbsp;heapSTRUCT_SIZE&nbsp;&nbsp;&nbsp;&nbsp;=&nbsp;<br />//(&nbsp;sizeof(&nbsp;xBlockLink&nbsp;)&nbsp;+&nbsp;(&nbsp;sizeof(&nbsp;xBlockLink&nbsp;)&nbsp;%&nbsp;portBYTE_ALIGNMENT&nbsp;)&nbsp;);<br />//我觉得这句话讲不出什么道理来,可能和linux中page之间的hole空间类似,是为了防止越界之类<br />//在空间上做的额外申请,因为xBlockLink数据区作为管理本段内存所使用的关键域,<br />//如果因为数据操作越界而被修改,那是相当可怕的尤其在动态内存申请、释放比较频繁的时候<br />//最后计算效果是这样的:如果sizeof(&nbsp;xBlockLink&nbsp;)=7[注:当然编译器不会让它是这个值,<br />//怎么着也是2的倍数,这里只是做个极端的例子(gliethttp)],<br />//那么heapSTRUCT_SIZE&nbsp;=&nbsp;7+3=10,不过实际在at91sam7s64上sizeof(&nbsp;xBlockLink&nbsp;)=8,所以heapSTRUCT_SIZE=8<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xWantedSize&nbsp;+=&nbsp;heapSTRUCT_SIZE;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;xWantedSize&nbsp;&&nbsp;heapBYTE_ALIGNMENT_MASK&nbsp;)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />//和方法1中一样,将xWantedSize调整为4的整倍数<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xWantedSize&nbsp;+=&nbsp;(&nbsp;portBYTE_ALIGNMENT&nbsp;-&nbsp;(&nbsp;xWantedSize&nbsp;&&nbsp;heapBYTE_ALIGNMENT_MASK&nbsp;)&nbsp;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;(&nbsp;xWantedSize&nbsp;&gt&nbsp;0&nbsp;)&nbsp;&&&nbsp;(&nbsp;xWantedSize&nbsp;&lt&nbsp;configTOTAL_HEAP_SIZE&nbsp;)&nbsp;)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />//xWantedSize是一个合法的数值,那么下面将检测自己是否还有这么大的空闲块<br />//因为在内存释放时不提供小内存块合并整理机制,所以小内存块会随着时间和不同大小内存块<br />//动态申请、释放的频繁发生最终变的越来越多,直到没有大内存可以申请到,全部都是小内存为止.<br /><br />//其实可以采用以前一篇**《一种轻巧的“内存动态分配管理机制”》中提到的动态内存分配和申请方式,<br />//**地址:http://blog.chinaunix.net/u1/38994/showart_351550.html<br />//可以将相邻的小块内存合并成大块内存,很好的解决了内存合并生成大内存块的问题.当然这种方法<br />//可能远远不如linux中的Buddy伙伴算法灵活,但是在嵌入式系统中应该能够满足用户对内存的基本需求了.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pxPreviousBlock&nbsp;=&nbsp;&xStart;//从空闲内存链表头开始找<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pxBlock&nbsp;=&nbsp;xStart.pxNextFreeBlock;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(&nbsp;(&nbsp;pxBlock-&gtxBlockSize&nbsp;&lt&nbsp;xWantedSize&nbsp;)&nbsp;&&&nbsp;(&nbsp;pxBlock-&gtpxNextFreeBlock&nbsp;)&nbsp;)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//当前pxBlock空闲块的太小<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pxPreviousBlock&nbsp;=&nbsp;pxBlock;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pxBlock&nbsp;=&nbsp;pxBlock-&gtpxNextFreeBlock;//看看下一个空闲块是否比xWantedSize大<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;pxBlock&nbsp;!=&nbsp;&xEnd&nbsp;)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />//没有到xEnd内存结尾处,所以确实是找到了一个大小比较适合空闲内存块<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pvReturn&nbsp;=&nbsp;(&nbsp;void&nbsp;*&nbsp;)&nbsp;(&nbsp;(&nbsp;(&nbsp;unsigned&nbsp;portCHAR&nbsp;*&nbsp;)&nbsp;pxPreviousBlock-&gtpxNextFreeBlock&nbsp;)&nbsp;+&nbsp;heapSTRUCT_SIZE&nbsp;);<br />//pxPreviousBlock-&gtpxNextFreeBlock~pxPreviousBlock-&gtpxNextFreeBlock+heapSTRUCT_SIZE之间的空间存放管理数据<br />//pxNextFreeBlock和xBlockSize<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pxPreviousBlock-&gtpxNextFreeBlock&nbsp;=&nbsp;pxBlock-&gtpxNextFreeBlock;//把本pxBlock从空闲链表上摘下<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;(&nbsp;pxBlock-&gtxBlockSize&nbsp;-&nbsp;xWantedSize&nbsp;)&nbsp;&gt&nbsp;heapMINIMUM_BLOCK_SIZE&nbsp;)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />//#define&nbsp;heapMINIMUM_BLOCK_SIZE&nbsp;&nbsp;&nbsp;&nbsp;(&nbsp;(&nbsp;size_t&nbsp;)&nbsp;(&nbsp;heapSTRUCT_SIZE&nbsp;*&nbsp;2&nbsp;)&nbsp;)<br />//如果本pxBlock剩余的字节数大于heapMINIMUM_BLOCK_SIZE,即:还可以用来申请heapSTRUCT_SIZE个字节数据<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//那么切割本pxBlock内存块(注意:xWantedSize是已经包含heapSTRUCT_SIZE的了)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//pxNewBlockLink为切割出来的新的空闲内存块首地址,已经4字节对齐<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pxNewBlockLink&nbsp;=&nbsp;(&nbsp;void&nbsp;*&nbsp;)&nbsp;(&nbsp;(&nbsp;(&nbsp;unsigned&nbsp;portCHAR&nbsp;*&nbsp;)&nbsp;pxBlock&nbsp;)&nbsp;+&nbsp;xWantedSize&nbsp;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//计算新空闲内存块包括heapSTRUCT_SIZE控制域和数据域的总大小<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pxNewBlockLink-&gtxBlockSize&nbsp;=&nbsp;pxBlock-&gtxBlockSize&nbsp;-&nbsp;xWantedSize;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pxBlock-&gtxBlockSize&nbsp;=&nbsp;xWantedSize;//将申请到的内存块的大小,填入内存块控制域<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//把切割出来的内存块添加到空闲内存链表xStart~xEnd之间<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//(注:xStart~xEnd是按空闲内存大小,以从小到达的顺序链起来的单向链表)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//也就是这样虽然看上去,FreeRTOS可以实现各种内存块的申请,但是因为切割出去的小内存块<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//在内存释放回收的时候,并不能自动进行内存合并整理,也就是空闲内存块不能变大,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//最后只能导致小内存空闲块越来越多,大内存空闲块越来越少,直到不能申请到大内存块<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//可以使用《一种轻巧的“内存动态分配管理机制”》中的方法很好的解决(gliethttp)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//**地址:http://blog.chinaunix.net/u1/38994/showart_351550.html<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;prvInsertBlockIntoFreeList(&nbsp;(&nbsp;pxNewBlockLink&nbsp;)&nbsp;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />//调度器解锁,此间会有若干处理,详细细节可以参见《浅析FreeRTOS_v4.5.0延时机制---vTaskDelay()的实现》<br />//**地址:http://blog.chinaunix.net/u1/38994/showart_392389.html<br />&nbsp;&nbsp;&nbsp;&nbsp;xTaskResumeAll();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;pvReturn;//返回申请到的内存数据区地址,pvReturn-heapSTRUCT_SIZE处存放了管理该pvReturn内存的控制数据<br />}<br />&lt2.2&gt第2种动态内存回收<br />void&nbsp;vPortFree(&nbsp;void&nbsp;*pv&nbsp;)<br />{<br />unsigned&nbsp;portCHAR&nbsp;*puc&nbsp;=&nbsp;(&nbsp;unsigned&nbsp;portCHAR&nbsp;*&nbsp;)&nbsp;pv;<br />xBlockLink&nbsp;*pxLink;<br />&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;pv&nbsp;)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;puc&nbsp;-=&nbsp;heapSTRUCT_SIZE;//内存数据区的前heapSTRUCT_SIZE空间存放了管理本段内存数据区的控制数据<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pxLink&nbsp;=&nbsp;(&nbsp;void&nbsp;*&nbsp;)&nbsp;puc;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vTaskSuspendAll();//锁住调度器<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />//把释放出来的内存块添加到空闲内存链表xStart~xEnd之间<br />//(注:xStart~xEnd是按空闲内存大小,以从小到达的顺序链起来的单向链表)<br />//也就是这样虽然看上去,FreeRTOS可以实现各种内存块的申请,但是因为切割出去的小内存块<br />//在内存释放回收的时候,并不能自动进行内存合并整理,也就是空闲内存块不能变大,<br />//最后只能导致小内存空闲块越来越多,大内存空闲块越来越少,直到不能申请到大内存块<br />//可以使用《一种轻巧的“内存动态分配管理机制”》中的方法很好的解决(gliethttp)<br />//**地址:http://blog.chinaunix.net/u1/38994/showart_351550.html<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;prvInsertBlockIntoFreeList(&nbsp;(&nbsp;(&nbsp;xBlockLink&nbsp;*&nbsp;)&nbsp;pxLink&nbsp;)&nbsp;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />//调度器解锁,此间会有若干处理,详细细节可以参见《浅析FreeRTOS_v4.5.0延时机制---vTaskDelay()的实现》<br />//**地址:http://blog.chinaunix.net/u1/38994/showart_392389.html<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xTaskResumeAll();<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}<br />//------------------------------------------------------------------------------<br />&lt3.1&gt第3种内存动态分配<br />void&nbsp;*pvPortMalloc(&nbsp;size_t&nbsp;xWantedSize&nbsp;)<br />{<br />void&nbsp;*pvReturn;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;vTaskSuspendAll();<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pvReturn&nbsp;=&nbsp;malloc(&nbsp;xWantedSize&nbsp;);//使用编译器自带的malloc函数<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;xTaskResumeAll();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;pvReturn;<br />}<br />&lt3.2&gt第3种动态内存回收<br />void&nbsp;vPortFree(&nbsp;void&nbsp;*pv&nbsp;)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;if(&nbsp;pv&nbsp;)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vTaskSuspendAll();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;free(&nbsp;pv&nbsp;);//使用编译器自带的free函数<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;xTaskResumeAll();<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}<br />//------------------------------------------------------------------------------<br />&nbsp;&nbsp;综上可知,FreeRTOS_v4.5.0对内存的动态分配支持的并不好,内存动态分配很简单,分配出去就可以了,<br />但是在分配出去的内存的动态回收上,还是欠佳的,可以引入linux中的Buddy伙伴算法,就是可能麻烦一些,<br />对linux中的Buddy伙伴算法,前段时间我也研读过,<br />可以参看《浅析armlinux-Buddy(伙伴)算法-释放合并回收函数__free_pages_ok()》,<br />**地址:http://blog.chinaunix.net/u1/38994/showart_357790.html<br />我觉得在内存动态分配上最好的改进方式是采用《一种轻巧的“内存动态分配管理机制”》<br /><br />**地址:http://blog.chinaunix.net/u1/38994/showart_351550.html中提到的那种内存动态分配与回收方式(gliethttp).
页: [1]
查看完整版本: 浅析FreeRTOS_v4.5.0内存分配与回收及其改进方案