当前位置:首页 > 公众号精选 > 嵌入式软件实战派
[导读]这次我成功将妹子约到了公司附近的咖啡馆,继续探讨RTOS的heap的技术特点。当我把准备好的数据和动图展示在她面前,她立马激动起来了。

这次我成功将妹子约到了公司附近的咖啡馆,继续探讨RTOS的heap的技术特点。当我把准备好的数据和动图展示在她面前,她立马激动起来了。仿佛我递出来的是一束花、钻戒,她惊讶不已,除了脸上少了几分娇羞……事情上这样的,我得好好重头讲一讲。1. 妹子的问题妹子好久没有问我问题了,想着应该是可以自己独立干项目了吧。这也是好事,毕竟是我亲自带出来的徒弟。但我还是怀念她经常问我问题的日子……
有一天傍晚快下班的时候,我问她,项目上的事自己能hold得住吗?有问题随时可以找我哦。
她想了想,欲言又止。
还没等她说话,我接着说,是遇到什么问题了吗?
“其实是这样的,我是遇到了OS上的一些疑惑问题,但也不是很要紧。看你那么忙,不好意思打扰你……”“哦……没事啊,什么问题呢?”她说,自从上次我跟她分析了OS占用内存的问题(见妹子告诉我她被欺负了)后,她就对OS的内存分配有不少疑惑,很想将它搞个一清二楚。这不,她现在的问题是,FreeRTOS里的Heap1~Heap5有什么区别?
心想:额……这次完犊子了,我还真没怎么研究过这几个Heap的区别。但是我不能在她面前说不行啊。
突然,心生一计,若有其事淡定地跟她说,这是个好问题,得好好探讨下。然后我顺手拿出手机看了看时间,问她,明天晚上有空么?
“有。”她回答很干脆。
这次,我得换个方式跟她讲解这个Heap,不能像以前那样了……
2. 熬夜研究heap于是,我背了笔记本回家,开始钻研这个heap的用法,得用丰富的知识和强有力的技能征服妹子。
首先,我将这几个heap的c文件移植到PC运行环境,用自动化手段分析其使用情况。我写了个main.c文件,分别与heap_1.c~heap_5.c进行编译。
主要思路是,向heap申请并释放内存,看看其地址占用空间,就一目了然了。
 addr1 = alloc_x(1); addr2 = alloc_x(2); addr4 = alloc_x(4); addr8 = alloc_x(8); addr16 = alloc_x(16); addr32 = alloc_x(32);  free_x(addr1); addr1 = alloc_x(1); free_x(addr4); addr2 = alloc_x(2); free_x(addr8); addr4 = alloc_x(4); addr4 = alloc_x(4); free_x(addr16); addr1 = alloc_x(1); addr2 = alloc_x(2); addr4 = alloc_x(4); addr8 = alloc_x(8); addr16 = alloc_x(16); addr1 = alloc_x(1); free_x(addr2); free_x(addr4); free_x(addr8); free_x(addr16); addr6 = alloc_x(6); addr10 = alloc_x(10);
这里面的alloc_xfree_x分别调用了pvPortMallocvPortFree,并打印一些信息。
void* alloc_x(size_t size){ void* addr = pvPortMalloc(size); size_t res = xPortGetFreeHeapSize(); printf("Alloc : addr=0x%p, size:0x%02X, remain:0x%04X\r\n", addr, size, res); return addr;} void free_x(void* addr){ vPortFree( addr); size_t res = xPortGetFreeHeapSize(); printf("Free  : addr=0x%p, remain:0x%04X\r\n", addr, res);}
总以为很顺利,谁知道,这heap依赖的头文件一层套一层……一狠心,大刀阔斧屏蔽了头文件里面的内容,手动添加heap需要的依赖项。
好不容易,编译通过了,在搞heap_1.c这个的时候,在运行到vPortFree,就挂了!查了下代码,发现heap_1原来是不允许free内存的。
void vPortFree( void * pv ){ /* Memory cannot be freed using this scheme.  See heap_2.c, heap_3.c and * heap_4.c for alternative implementations, and the memory management pages of * https://www.FreeRTOS.org for more information. */ ( void ) pv;  /* Force an assert as it is invalid to call this function. */ configASSERT( pv == NULL );}
因为它只实现了pvPortMalloc而没实现vPortFree,所以这个vPortFree是没用的,仅仅是个兼容性接口而已。
接着,把后面的heap_2~heap_5的编译运行问题一个个搞定了。
Note:我把整个工程打包好了,关注公众号“嵌入式软件实战派”,在后台回复“heap”即可获得下载链接。
通过输出的log信息,我还细心地做了个内存分配动图。
搞完这一波,看了下时间,竟然是晚上12点了。
然后,我居然兴奋得睡不着,想着怎么跟她讲解这个技术问题。
第二天,突发奇想,约她在公司附近的咖啡馆!她居然爽快地答应了!!
3. 促膝长谈晚上下班,我们一起到了咖啡厅,就像一对小……伙伴程序员,背着笔记本电脑。跟异性来这种地方,我还有些不好意思。
为了避免尴尬,单刀直入,打开笔记本,把准备好的材料跟她一一讲解。
“师兄,我们不点个咖啡吗?”
“呵呵呵……其实……你喜欢和什么?”
……

她说晚上不喝咖啡,于是我给她点了一杯奶茶,然后迫不及待地跟她将这个heap的情况。

一开始,我用官方的文档解释给她说明了下总体的情况:

我问她,“你知道FreeRTOS为什么不用C库中的malloc()free()函数来分配和释放内存吗?”

“因为,不安全。”

我听她这么肯定的说,想着她肯定是对RTOS有很深入的认识的。

是的,C库中的malloc()free()函数:

1. they are not always available on embedded systems,

2. they take up valuable code space,

3. they are not thread safe, and

4. they are not deterministic (the amount of time taken to execute the function will differ from call to call)

FreeRTOS
“所以,FreeRTOS的几个heap是为了解决这几个问题的。”
她点了点头,然后低头喝了一口奶茶。我看她那手捧奶茶的温柔,恰好点缀了窗外的夕阳……多想多停留在这一刻,但我怕她看到我在看她,接着说:“那么,这几个heap有什么区别呢?总的来说是这样的。”

heap_1 - 最简单的实现形式,不支持Free内存;

heap_2 - 允许内存Free,但不会合并free的内存块;

heap_3 - 是malloc() 和free() 的抽象层,多加了线程安全措施;

heap_4 - 合并free的块,避免碎片

heap_5 - 类似heap_4,增加了块内存段操作。

“嗯!”她轻声说。其实她已经看过了这些解释了,但是不是很理解,她想深入一点的,深入一点的学习。“‘Talk is cheap’,那么,我们直接上代码吧。”
她呵呵大笑。笑的样子也特别可爱。
“我们就按照官方的解释,来验证下。我写了段测试代码,你看看这段log就知道了。”
Base Addr: 0x407080Alloc : addr=0x00407080, size:0x01, remain:0x27F0Alloc : addr=0x00407088, size:0x02, remain:0x27E8Alloc : addr=0x00407090, size:0x04, remain:0x27E0Alloc : addr=0x00407098, size:0x08, remain:0x27D8Alloc : addr=0x004070A0, size:0x10, remain:0x27C8Alloc : addr=0x004070B0, size:0x20, remain:0x27A8Free : addr=0x00407080, remain:0x27A8Alloc : addr=0x004070D0, size:0x01, remain:0x27A0Free : addr=0x00407090, remain:0x27A0Alloc : addr=0x004070D8, size:0x02, remain:0x2798Free : addr=0x00407098, remain:0x2798Alloc : addr=0x004070E0, size:0x04, remain:0x2790Alloc : addr=0x004070E8, size:0x04, remain:0x2788Free : addr=0x004070A0, remain:0x2788Alloc : addr=0x004070F0, size:0x01, remain:0x2780Alloc : addr=0x004070F8, size:0x02, remain:0x2778Alloc : addr=0x00407100, size:0x04, remain:0x2770Alloc : addr=0x00407108, size:0x08, remain:0x2768Alloc : addr=0x00407110, size:0x10, remain:0x2758Alloc : addr=0x00407120, size:0x01, remain:0x2750Free : addr=0x004070F8, remain:0x2750Free : addr=0x00407100, remain:0x2750Free : addr=0x00407108, remain:0x2750Free : addr=0x00407110, remain:0x2750Alloc : addr=0x00407128, size:0x06, remain:0x2748Alloc : addr=0x00407130, size:0x0A, remain:0x2738
她准备站起来,把头凑过来看,我把笔记本转过去给她。然后我继续解释说,“这个Free是没有意义的”。
“哦?”她似乎有些不相信,然后试图口算这些地址值。
“我再给个图你看看。”

“哇哦……这颜色是什么意思,代表申请的内存块吗?怎么还有这么多空隙的?”她低声问道,似乎有点好奇,又有点不是很相信的样子。
“是的,要颜色的地方是表示内存申请占有的地方,至于空隙嘛,我一会再跟你解释下。”我接着说,“歪着头怎么看呢!要不坐过来我这边,我还有一个动图。”

“厉害!这都可以做出来,走心了……”
“你仔细看,其实这个vPortFree执行的地方,内存是没有变化的。”
“真的哦,heap_1是不能释放内存的。”突然,我觉得我很有成就感。
“那么,为什么会有这么多空隙的呢?我们看看这段代码就清楚了。”
void * pvPortMalloc( size_t xWantedSize ){ void * pvReturn = NULL; static uint8_t * pucAlignedHeap = NULL;  /* Ensure that blocks are always aligned. */ #if ( portBYTE_ALIGNMENT != 1 ) { if( xWantedSize & portBYTE_ALIGNMENT_MASK ) { /* Byte alignment required. Check for overflow. */ if ( (xWantedSize + ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) )) > xWantedSize ) { xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); } else { xWantedSize = 0; } } } #endif
“哦……原来最大多占了一个portBYTE_ALIGNMENT的空间。”她端详了一阵这个代码说。
“所以,官方有说,自从有了static的内存分配方法,就很少用这个heap_1了。”
“嗯!”她似乎很满足的样子,伸手把奶茶拿过来,接着喝了一口。
我也喝了一口咖啡,突然觉得这个咖啡不苦了。她起身,准备要坐回去。
“等下,我这还有其他数据,给你看看heap_2的情况。”我说后,她慢慢坐了下来。夕阳已慢慢落在了城市的高楼之中,道路上依然车水马龙,而安静的咖啡馆有种说不出来的温馨。
“那么heap_2有什么不一样呢?我们直接看图吧。”

“咦?怎么有更多的孔隙了?”
“是啊,我也纳闷,但看了下源码,确实会这样,其中有一段是这样的。”
 /* The wanted size must be increased so it can contain a BlockLink_t * structure in addition to the requested amount of bytes. */ if( ( xWantedSize > 0 ) && ( ( xWantedSize + heapSTRUCT_SIZE ) >  xWantedSize ) ) /* Overflow check */ { xWantedSize += heapSTRUCT_SIZE;  /* Byte alignment required. Check for overflow. */ if( ( xWantedSize + ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ) ) > xWantedSize ) { xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) ); configASSERT( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) == 0 ); } else { xWantedSize = 0; } }
我接着解释说,“你看,用heap_2每次申请一段内存,都要多占一段heapSTRUCT_SIZE和一段portBYTE_ALIGNMENT 空间。”
“哦,怪不得,我们项目定义了32K的RAM都差不多用完了,我算了下实际的分配,还差很远,原来问题在这呢!”她似乎有种茅舍顿开的感觉。
“那么heap_3又是怎样的呢?”她主动问我要图片来看了。

“我用PC上位机软件模拟的,heap_3用的是标准库的malloc()和free(),似乎没啥规律,其实没什么参考价值的。”
“好吧……那heap_4呢?”她似乎有点失落的样子,而又“肆无忌惮”起来,直问我要图看。
我不慌不忙打开了这个图。

“好像跟heap_2一样的哦……”
“是的,很像。但是,有个很重要的区别,你看这最后一帧内容,特别是最后紫色的这块。”我特意将heap_2的和heap_4的拿出来对比了下。

“看起来似乎heap_4更省空间……哈哈!”看着这两个图的对比,她乐了起来,像个天真的孩子。
“虽然还是很多孔隙,但是free掉的空间是可以合并的,这个heap_4的好处就在这了。”
“是的,师兄你真厉害!”
“哈哈!”
“对了,还有heap_5的呢?”

“哦?跟heap_4的没啥区别哦……”这说话拉长的语调,越来越可爱了。

“效果看起来,确实是一样的,但是heap_5是可以跨不连续区域的。官方文档也是这么说的。”

This scheme uses the same first fit and memory coalescence algorithms as heap_4, and allows the heap to span multiple non adjacent (non-contiguous) memory regions.

FreeRTOS
“那么,它是怎么跨区域的呢?”她突然好奇起来。
“给你看段代码吧。其实它多了一个函数。”
void vPortDefineHeapRegions( const HeapRegion_t * const pxHeapRegions )
“这个const HeapRegion_t * const pxHeapRegions就是定义不同区域段的。”
“怎么分段的呢?”“那,我们看这个官方的例子。”
// HeapRegion_t xHeapRegions[] =// {//     { ( uint8_t * ) 0x80000000UL, 0x10000 }, << Defines a block of 0x10000 bytes starting at address 0x80000000//     { ( uint8_t * ) 0x90000000UL, 0xa0000 }, << Defines a block of 0xa0000 bytes starting at address of 0x90000000//     { NULL, 0 }                << Terminates the array.// };// vPortDefineHeapRegions( xHeapRegions ); << Pass the array into vPortDefineHeapRegions().


本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭