尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

malloc 代码之 set_foot

malloc 代码之 set_foot 这个宏用于在空闲 chunk 的尾部写入一个脚部footer记录该 chunk 自身的大小。它和set_prev_size是配套的但作用方向相反。源码定义/* Set size at footer (only when chunk is not in use) */ #define set_foot(p, s) (((mchunkptr) ((char *) (p) (s)))-mchunk_prev_size (s))逐步拆解1. 参数pp是一个mchunkptr指向当前空闲 chunk 的起始地址。2. 参数ss是当前空闲 chunk 的总大小。3. 计算(char *) (p) (s)将p转为char *加上s得到下一个物理相邻 chunk 的起始地址。4.-mchunk_prev_size (s)将s写入下一个 chunk 的prev_size字段。核心作用为下一个 chunk 提供向前合并的信息set_foot的本质是在空闲 chunk 的尾部即下一个 chunk 的头部写入自己的大小让下一个 chunk 知道前面有一个多大的空闲块。图示------------------------------------ | chunk A (空闲) | chunk B | | prev_size | size | prev_size | size | ------------------------------------ ^ │ set_foot(A, size_A) 写入这里 即 B-prev_size size_A效果当 chunk B 将来被释放时它能通过prev_size字段知道 chunk A 的大小。如果 chunk A 仍然空闲B 就可以向前合并到 A形成一个更大的空闲块。与set_prev_size的关系这两个宏看起来很像但调用者和作用对象不同宏调用时机作用对象写入位置set_prev_size(p, sz)释放/合并时当前 chunkpp-prev_sizeset_foot(p, s)设置空闲块时下一个 chunknext_chunk(p)-prev_size关键区别set_prev_size是被动的当自己的前一个块释放时自己作为下一个块prev_size被更新。set_foot是主动的当自己变成空闲块时主动去更新下一个块的prev_size。实际上set_foot(p, s)等价于set_prev_size(next_chunk(p), s);只是set_foot用地址计算直接完成了这个操作。前提条件only when chunk is not in use注释明确说明只有当 chunk 处于空闲状态时才能调用set_foot。为什么因为set_foot会写入next_chunk(p)-prev_size字段。这个字段的位置正好是当前 chunk 的用户数据区的最后一个字节或最后几个字节。如果当前 chunk空闲用户数据区没有有效数据prev_size字段可以被安全地复用为脚部。如果当前 chunk已分配用户数据区可能正在使用写入prev_size会破坏用户数据。图示chunk A 已分配时: ------------------------------------ | chunk A | chunk B | | ... 用户数据 ... | prev_size | size | ------------------------------------ ^ │ chunk A 的用户数据可能一直写到这里 此时写入 prev_size 会破坏用户数据 chunk A 空闲时: ------------------------------------ | chunk A (空闲) | chunk B | | ... 空闲 ... | prev_size | size | ------------------------------------ ^ │ chunk A 空闲用户数据无效 此时可以安全写入 prev_size实际使用场景1. 将 chunk 放入空闲链表时static void _int_free(mstate av, mchunkptr p, int have_lock) { size_t size chunksize(p); // ... 合并逻辑 ... // 将合并后的空闲块放入 unsorted bin set_foot(p, size); // 在下一个 chunk 的 prev_size 中记录本块大小 set_head(p, size | PREV_INUSE); // 设置本块的 size }2. 从 Top Chunk 切割时// 从 Top Chunk 切出一块后剩余部分成为新的 Top Chunk set_head(remainder, remainder_size | PREV_INUSE); set_foot(remainder, remainder_size);3. 合并相邻空闲块时// 合并 p 和 next 后 size chunksize(next); set_head(p, size | PREV_INUSE); set_foot(p, size); // 更新下一个块的 prev_size完整示例假设有两个物理相邻的 chunk地址 大小 状态 0x804b000 0x20 空闲 (chunk A) 0x804b020 0x30 已分配 (chunk B)调用set_foot(0x804b000, 0x20)计算下一个 chunk 地址0x804b000 0x20 0x804b020 写入0x804b020-prev_size 0x20结果0x804b000: prev_size ?, size 0x21 (空闲PREV_INUSE1) 0x804b020: prev_size 0x20, size 0x31 (chunk B)现在 chunk B 的prev_size记录了 chunk A 的大小。如果 chunk B 将来被释放它就能通过prev_size找到 chunk A 并合并。相关宏对比宏作用方向前提set_foot(p, s)在下一个 chunk 的prev_size中写入s向后chunkp空闲set_prev_size(p, sz)在当前 chunk 的prev_size中写入sz向前前一个 chunk 空闲prev_size(p)读取当前 chunk 的prev_size-前一个 chunk 空闲set_head(p, s)设置当前 chunk 的size-总是有效set_foot和set_prev_size实际上是同一个操作的不同视角set_foot(p, s) ≡ set_prev_size(next_chunk(p), s)总结要点说明功能在空闲 chunk 的尾部下一个 chunk 的prev_size写入自身大小前提只有 chunk 空闲时才能调用用途为下一个 chunk 提供向前合并所需的大小信息配对操作通常与set_head配合使用等价形式set_foot(p, s) set_prev_size(next_chunk(p), s)一句话理解set_foot(p, s)是空闲 chunk 的自我声明——它在自己的尾部下一个 chunk 的prev_size字段写下自己的大小告诉下一个 chunk我在这里大小是s如果你将来被释放可以来找我合并。
返回列表