rtos heap_4.c模型分析 待完善
作者:互联网
heap_4.c
/ *放在每个分配的内存开头的结构的大小块必须按正确的字节对齐。堆按照8字节对齐 * /
xHeapStructSize = ( ( sizeof( BlockLink_t ) + ( ( ( size_t ) portBYTE_ALIGNMENT_MASK ) - ( size_t ) 1 ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK ) );
= 8 + (8 - 1)&~(0x0007) = 8
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. */
} BlockLink_t;
block结构体包括一个指向自己类型的指针,32位系统指针长度为4字节;一个u32的block大小。
整个结构体8字节。
static BlockLink_t xStart, *pxEnd = NULL;
xStart是静态变量两个成员初始化为0,pxEnd,是指针类型,指针成员初始化为0,未初始化的block大小是个随机数。
location
uint8 ucHeap[12288] 0x1FFFE314
xStart 0x20001314 //0x20001314是xStart的地址,同时也是xStart第一个成员*pxNextFreeBlock的地址
pxEnd 0x2000131c //heap_2 xEnd
ucHeap 是定义的内存堆数组,长度是12*1024 = 12288。(0x3000)
从低地址到高地址,堆区的地址空间范围:0x1FFFE314 - 0x20001313
ucHeap[0]地址:0x1FFFE314, ucHeap[12287]地址:0x20001313 一共 12288字节 。随后紧跟的就是静态存储区的xStart,pxEnd
prvHeapInit:
取出初始地址,判断ucHeap地址不是8字节的整数,将低地址的部分截除掉一部分
if( ( ulAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
{
ulAddress += ( portBYTE_ALIGNMENT - 1 );// 0x1FFFE314 +7 = 0x1FFFE31B
ulAddress &= ~( ( uint32_t ) portBYTE_ALIGNMENT_MASK );// 0x1FFFE31B --> 0x1FFFE318
xTotalHeapSize -= ulAddress - ( uint32_t ) ucHeap;//因为截取掉了4字节,所以堆长度变为了12288 -( 0x1FFFE318-0x1FFFE314) = 12284(0x2FFC)
}
初始化xStart //xStart用于保存指向 空闲列表中第一项 的指针块。//空闲列表中第一项在最开始时,就是第一个block
如图
初始化pxEnd:/ * pxEnd用于标记可用块列表的末尾并插入在堆空间的末尾。 * /
0x1FFFE318 + 0x0002FFC = 0x20001314(这个地址正好是xStart的地址 &xStart = 0x20001314,所以它是不可用的,末尾的地址应该是内存数组堆中的最后一块)
此时堆空间的排布
0x1FFFE314 0x1FFFE318 --此时空闲堆空间长度 12276-- 0x2000130c 0x20001314
地址再减去末尾的8字节后,发现此时得到的地址是不对齐的,//0x2000130c除不尽 长度12276/8 = 1534.5 也是除不尽的,因为最开始截去掉了4字节
原因是12k长度的地址空间,头不对齐的话,尾肯定也是不对齐的,所以需要再进行一次对齐,得到的尾地址如下:
ulAddress &= ~( ( uint32_t ) portBYTE_ALIGNMENT_MASK ); //高地址对齐只需要去除尾数>8的部分即可
最终的末尾地址:0x20001308
pxEnd = 0x20001308 (ucHeap + 12276) // &pxEnd = 0x2000130c
所以堆长度变为了12272,此时堆的排布:
0x1FFFE314 0x1FFFE318 --此时空闲堆空间长度 12272(0x2FF0) -- 0x20001308 0x20001314
有效的范围 0x1FFFE318 -- 0x20001308
xStart = 0x1FFFE318
pxEnd->pxNextFreeBlock = 0x20001308
首先,有一个空闲块,其大小可容纳整个堆空间,减去pxEnd占用的空间。因为pxEnd所在在位置就是堆空间的首地址,如图为堆空间排布开始 的部分:
将pxEnd 内容 放在堆首地址的同时,因为xStart 指向的也是堆的首地址0x1FFFE318,
也即同时初始化了 xStart的pxNextFreeBlock所指向的pxNextFreeBlock,同时对应的blocksize也是12272 如图:
到此初次调用molloc导致的堆初始化已经完成。
回到malloc函数:
要申请的内存大小
xWantedSize = 512
需要加上block头 8 字节
xWantedSize = 520
需要再判断申请大小是否对齐8字节,(这里正好对齐,所以跳过,520大小不变)
再判断申请的内存大小是否大于当前空闲堆大小
分配内存过程:
pxBlock 与 pxPreviousBlock :如图
pxBlock表示当前的block从0x1FFFE318开始,blocksize 12276,下一个block地址是0x20001308,大小是0(即末尾block
pxPreviousBlock 是操作block的中转,即xStart;
而xStart的初始化:即上面讲到的 空闲列表中第一项,在最开始时是第一个block 所以pxNextFreeBlock = 0x1FFFE314
因为此时整个堆中只有两个block,第一个block的下一个block地址:即start的pxNextFreeBlock的pxNextFreeBlock = 0x20001308
xStart此时并不表示block,所以它的blocksize = 0
如图、
pvReturn 因为要新分配一个block,所以在第一个block地址的基础上,加8: block头
pvReturn = 0x1FFFE320 (ucHeap + 12)
随后将经历如下步骤:
该块正在返回使用,因此必须取出空闲块列表。
如果块大于要求,则可以将其拆分为二
此块将被分成两部分。 创建一个新的跟随请求的字节数的块。
计算从单个块分割的两个块的大小
将新块插入空闲块列表
数据可视化分析:
因为0x1FFFE320 已经大于 0x1FFFE318,所以要将最大的空闲block取出。
原本是第一block 大小 12272 (0x1FFFE318
分成第一block和第二block
第一block的size 就是520 (0x1FFFE318
第二block的size 就是 12272 - 520 =11752 (0x1FFFE320
要将第二block插入到链表中去。
并 更新xStart,下次从0x1FFFE320开始操作 //0x1FFFE318 - 0x1FFFE320 已经分配出去了
更新剩余空闲block大小。
pxNewBlockLink 0x1FFFE520 (ucHeap + 524)
给新block 剩余的空间长度
pxNewBlockLink->xBlockSize = 11752
此时的block排布:
0x1FFFE318 (ucHeap + 4) (520 )
0x1FFFE520 (ucHeap + 524) (11752)
0x20001308 (ucHeap + 12276) (0)
标签:0x1FFFE318,ucHeap,模型,rtos,地址,heap,xStart,pxEnd,block 来源: https://www.cnblogs.com/yyyyloveu/p/14364427.html