OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4609|回复: 3

FreeRTOS V9.0.0堆内存管理问题

[复制链接]

11

主题

49

帖子

0

精华

初级会员

Rank: 2

积分
190
金钱
190
注册时间
2016-11-30
在线时间
92 小时
发表于 2020-3-4 18:42:51 | 显示全部楼层 |阅读模式
1金钱
FreeRTOS内存管理代码中,堆内存8字节对齐的时候为什么没有去判断堆内存是否是8字节对齐的,而是直接做对齐工作。如果编译器恰好把堆内存分配到了8字节对齐的地址,那么就不用内存对齐了。根据FreeRTOS源码可以看出,如果堆内存恰好是8字节对齐,那么会浪费堆内存的前8个字节空间。下边这代码是堆内存空间初始化的过程:

                if( pucAlignedHeap == NULL )//判断是否是第一次申请内存 如果第一次申请内存则8字节对齐堆内存
                {
                        /* Ensure the heap starts on a correctly aligned boundary. */
                        //直接对堆内存做一次8字节对齐                                                               
                        //                                                                                                         数组第8个元素                        &                        FFFF FFF8                                                                                                                                                                                                                                
                        pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
                }



EIASCL2LU9_09Z8BVP5FA8W.png
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

11

主题

49

帖子

0

精华

初级会员

Rank: 2

积分
190
金钱
190
注册时间
2016-11-30
在线时间
92 小时
 楼主| 发表于 2020-3-4 18:49:30 | 显示全部楼层
uint8_t ucHeap[configTOTAL_HEAP_SIZE] __attribute__((at(0x2000A000)));//故意编译到8字节对齐的地址

        pbuffer = pvPortMalloc(2);//此处确实是上电第一次调用pvPortMalloc函数
        printf("ucHeap起始地址 = %p\r\n",ucHeap);
        printf("pbuffer = %p\r\n",pbuffer);

输出结果:
ucHeap起始地址 = 2000a000
pbuffer = 2000a008

回复

使用道具 举报

0

主题

113

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2538
金钱
2538
注册时间
2019-10-18
在线时间
403 小时
发表于 2020-3-4 19:33:41 | 显示全部楼层
本帖最后由 decai 于 2020-3-4 19:36 编辑

你申请内存的时候,申请的内存基础上会在头部多申请8个字节存放该块内存的信息
所以你申请的时候2字节,实际会申请到2+8=10个内存,10个字节对齐到12个字节(16个?)
申请的12个字节确实是刚好开始的2000a000,但是前8个字节系统征用了,给你的就是这12个字节的第8个元素开始的2000a008.没毛病
你可以试试再申请一次,会发现又丢了好多字节内存
回复

使用道具 举报

11

主题

49

帖子

0

精华

初级会员

Rank: 2

积分
190
金钱
190
注册时间
2016-11-30
在线时间
92 小时
 楼主| 发表于 2020-3-5 13:24:17 | 显示全部楼层
decai 发表于 2020-3-4 19:33
你申请内存的时候,申请的内存基础上会在头部多申请8个字节存放该块内存的信息
所以你申请的时候2字节,实际 ...

你说的用8个字节存放该块的内存信息,这个是heap2,heap4和heap5用到的方法,heap1并没有用结构管理内存信息。
而且heap2,heap4,heap5也有同样的问题(因为堆内存对齐的时候没有判断编译器分配的内存是否恰好是8字节对齐的)。
举个例子,验证一下:
使用heap2内存管理方案,当编译器把内存编译到0x2000a000内存地址(这个地址是8字节对齐的),
理论上我们第一次申请内存得到的起始地址是2000a008(因为前8个字节用于管理内存)。
实际输出如下:
ucHeap起始地址 = 0x2000a000
pbuffer = 0x2000a010
因为前边漏掉8个字节,再加上8个字节的管理信息,正好是16个字节 所以输出的是 0x2000a010而非 0x2000a008
如何改善:
pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
改为
pucAlignedHeap = ( uint8_t * ) ( ( ( portPOINTER_SIZE_TYPE ) &ucHeap[ portBYTE_ALIGNMENT -1 ] ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) );
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-25 21:31

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表