内存管理中的字节对齐算法

内存管理模块里,在内存块和内存池的分配时都需要用到字节对齐,今天来分析一下字节对齐的实现方法

基本实现

首先看align的基本的实现:

使用的时候:

ini 复制代码
block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE);

宏定义是这样的

scss 复制代码
#define RT_ALIGN_SIZE   4
#define RT_ALIGN(size, align)        (((size) + (align) - 1) & ~((align) - 1))
#define RT_ALIGN_DOWN(size, align)      ((size) & ~((align) - 1))

RT_ALIGN_DOWN(size, align),向下对齐,通过按位与操作&和掩码~(((align) - 1))来将结果向下对齐到最近的align的倍数

怎么实现的呢:

首先,这里align 应该是一个2的幂,比如1(表示按字节对齐)、2(按字对齐,假设字是16位)、4(按双字对齐,假设双字是32位)、8(按四字对齐,假设四字是64位)等。

然后,我们来看掩码 ~(((align) - 1)) 的生成过程:

(align) - 1:如果 align 是2的幂,那么它在二进制表示中只有一个位是1(例如,align 为4时,二进制是 0100),减1后,这个1会变成0,它后面的所有0都会变成1(例如,0100 - 1 = 0011)。

~:按位取反操作会将所有1变为0,所有0变为1。因此,如果 (align) - 1 的结果是 0011,那么取反后就得到 1100

现在,我们有了掩码 1100...(实际上前面还有很多个1,直到达到与 size 相同的位数)。这个掩码的特点是其低位的 log2(align) 个位都是0,其余位都是1。

接下来,我们将这个掩码与 size 进行按位与操作 &

由于掩码的低 log2(align) 位是0,所以 size 的这些低位将被清零。

size 的其余高位则保持不变,因为这些位与掩码的对应位都是1,按位与操作不会改变这些位的值。

这个按位与操作的效果是将 size 向下调整到最近的 align 的倍数。这是因为任何大于或等于 align 的数,在二进制表示中,其低 log2(align) 位至少有一个是1。将这些位清零后,我们就得到了不大于 size 的最大的 align 的倍数。

举个例子,假设 size13(二进制 1101),align4(二进制 0100)。那么掩码就是 1100~((4 - 1)) 的结果)。执行按位与操作 13 & 1100 得到 12(二进制 1100),这正是小于或等于13的最大的4的倍数。

JX_ALIGN(size, align)是向上对齐,就是把size向上对齐到最近的align的倍数,这里就是把block_size对齐到4的倍数,实现的方法是,先size加(align-1),保证超过size所在的当前align的倍数,从而进入下一个align的倍数区间。然后再通过按位与操作&和掩码~(((align) - 1))来将结果向下对齐到最近的align的倍数.

拓展

另外发现一个有意思的事情,单个内存块是向上对齐的,整个内存池是向下对齐的

ini 复制代码
/* initialize memory pool */
    mp->start_address = start;
    mp->size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);

    /* align the block size */
    block_size = RT_ALIGN(block_size, RT_ALIGN_SIZE);
    mp->block_size = block_size;

仔细读了一遍源码之后想明白了

这个操作是在rt_mp_init()函数里的

他是对于已经申请到了的内存对象进行初始化,就是说这里的size就是实际的这个内存池的大小,假如是向4对齐,这个size是63,我要用的时候只能对齐为60,因为实际就是63kb大小,只能向下对齐。

之后内存块向上对齐,保证够用。

具体能分成多少内存块,是align完的size/block_size

所以主要原因就是,这个操作不是在内存池create的时候,是在init的时候

相关推荐
jjyangyou2 小时前
物联网核心安全系列——物联网安全需求
物联网·算法·安全·嵌入式·产品经理·硬件·产品设计
憧憬一下18 小时前
Pinctrl子系统中Pincontroller和client驱动程序的编写
arm开发·嵌入式·c/c++·linux驱动开发
蓝天居士18 小时前
ES8388 —— 带耳机放大器的低功耗立体声音频编解码器(4)
嵌入式·音频·es8388
田三番21 小时前
使用 vscode 简单配置 ESP32 连接 Wi-Fi 每日定时发送 HTTP 和 HTTPS 请求
单片机·物联网·http·https·嵌入式·esp32·sntp
启明智显1 天前
AI笔筒操作说明及应用场景
人工智能·嵌入式硬件·嵌入式·ai大模型·启明智显·esp32-s3
FreakStudio1 天前
全网最适合入门的面向对象编程教程:58 Python字符串与序列化-序列化Web对象的定义与实现
python·单片机·嵌入式·面向对象·电子diy
Projectsauron5 天前
【STM32】通过 DWT 实现毫秒级延时
stm32·嵌入式·dwt
云中双月6 天前
如何使用Ida Pro和Core Dump文件定位崩溃位置(Linux下无调试符号的进程专享)
linux·嵌入式·gdb·调试·gcc·崩溃·ida pro·ulimit·core dump·cross compile
L_Z_J_I7 天前
超子物联网HAL库笔记:准备篇
笔记·物联网·嵌入式
飞凌嵌入式7 天前
FET113i-S核心板已支持RISC-V,打造国产化降本的更优解 -飞凌嵌入式
嵌入式硬件·嵌入式·risc-v·飞凌嵌入式