深入浅出rust内存对齐

在 Rust 中,内存对齐是一个重要的概念,它涉及到数据在内存中的存储方式,以及如何优化内存访问的效率。往往一门语言的内存布局以及对齐方式决定了一门语言的性能,因此学会并深入理解rust中内存布局会让我们写出高性能的rust代码,我们就从以下介个方面来对rust的内存对齐:

  1. **内存对齐的定义**:
  • 内存对齐要求数据在内存中的存储位置满足特定的对齐要求。大多数计算机体系结构要求某些数据类型的地址必须是特定大小的整数倍 。
  1. **对齐的自然数倍**:
  • `address` 与 `size` 都必须是对齐位数 `alignment` 的自然数倍。例如,对齐位数为 2 字节的变量值仅能保存于偶数位的内存地址上 。
  1. **对齐位数**:
  • 对齐位数 `alignment` 必须是 2 的自然数次幂,即 `alignment = 2^N` 且 `N` 是小于或等于 29 的自然数 。
  1. **存储宽度**:
  • 存储宽度 `size` 是有效数据长度加上对齐填充位数的总和字节数 。
  1. **对齐填充**:
  • 由于 `address`、`size` 与 `alignment` 之间存在倍数关系,程序对内存空间的利用会出现冗余与浪费,这些被浪费掉的部分被称为对齐填充 `alignment padding` 。
  1. **小端和大端填充**:
  • 对齐填充分为小端填充 `Little-Endian padding` 和大端填充 `Big-Endian padding`,分别对应 0 填充位出现在有效数据右侧的低位和左侧的高位 。
  1. **默认对齐规则**:
  • Rust 中,默认情况下,数据类型的对齐方式是与其大小相对应的。例如,`u32`、`i32`、`f32` 和指针类型对齐到 4 字节边界;`u64`、`i64` 和 `f64` 类型对齐到 8 字节边界 。
  1. **手动控制对齐**:
  • 可以通过 `#[repr(align(n))]` 注解来手动控制结构体或枚举的对齐方式 。
  1. **紧凑对齐**:
  • 通过 `#[repr(packed)]` 属性可以手动设置紧凑对齐方式,这会忽略默认的对齐规则,使结构体占用更少的空间 。
  1. **内存对齐的影响**:
  • 内存对齐是编译器或虚拟机(比如 JVM)的工作,不需要人为指定,但是作为开发者需要了解内存对齐的规则,这有助于编写出合理利用内存的高性能程序 。

这些规则和特性确保了 Rust 程序在不同平台上的内存访问效率和兼容性。通过理解内存对齐,开发者可以更好地优化程序性能和内存使用。

例子

在 Rust 中,你可以使用 `#[repr(align(n))]` 属性来指定结构体或枚举的对齐要求。以下是一些关于内存对齐的例子:

默认对齐

```rust

#[repr(C)]

struct AlignedStruct {

a: u8,

b: u32,

c: u64,

}

fn main() {

println!("Size of AlignedStruct: {}", std::mem::size_of::<AlignedStruct>());

println!("Align of AlignedStruct: {}", std::mem::align_of::<AlignedStruct>());

}

```

在这个例子中,`AlignedStruct` 使用默认对齐,`u8`、`u32` 和 `u64` 会根据它们的大小自然对齐。`u8` 不需要对齐,`u32` 需要 4 字节对齐,`u64` 需要 8 字节对齐。因此,`AlignedStruct` 的对齐要求将由最大的对齐要求决定,即 8 字节。

手动指定对齐

```rust

#[repr(align(4))]

struct ManuallyAligned {

a: u8,

b: u32,

c: u64,

}

fn main() {

println!("Size of ManuallyAligned: {}", std::mem::size_of::<ManuallyAligned>());

println!("Align of ManuallyAligned: {}", std::mem::align_of::<ManuallyAligned>());

}

```

在这个例子中,我们手动将 `ManuallyAligned` 的对齐要求设置为 4 字节。这意味着结构体在内存中的地址必须是 4 的倍数。这可能会导致一些填充,以确保 `u64` 成员 `c` 也符合这个对齐要求。

紧凑对齐

```rust

#[repr(packed)]

struct PackedStruct {

a: u8,

b: u32,

c: u64,

}

fn main() {

println!("Size of PackedStruct: {}", std::mem::size_of::<PackedStruct>());

println!("Align of PackedStruct: {}", std::mem::align_of::<PackedStruct>());

}

```

在这个例子中,`PackedStruct` 使用 `#[repr(packed)]` 属性,这意味着结构体将尽可能紧凑地排列,忽略默认的对齐规则。这可能会导致内存访问效率降低,但可以节省空间。

对齐填充

```rust

#[repr(C, align(8))]

struct AlignedWithPadding {

a: u8,

b: u32,

}

fn main() {

let aligned_with_padding = AlignedWithPadding { a: 1, b: 2 };

unsafe {

println!("Address of a: {}", aligned_with_padding as *const _ as usize);

println!("Address of b: {}", &aligned_with_padding.b as *const _ as usize);

}

}

```

在这个例子中,`AlignedWithPadding` 被指定为 8 字节对齐。由于 `a` 是 `u8` 类型,它后面会有 3 字节的填充,以确保 `b` 是 8 字节对齐的。我们使用 `unsafe` 代码来打印出 `a` 和 `b` 的地址,以展示对齐的效果。

请注意,手动控制对齐和紧凑对齐可能会影响程序的性能和跨平台兼容性,因此应谨慎使用。在大多数情况下,依赖 Rust 的默认对齐策略是最佳实践。、

如果我的文章对您有所帮助,还请一键三连我的小绿书,从此不迷路,您的一键三连是对我最大的鼓励和支持,因为有您的鼓励和支持让我一路坚持输出,万分感谢您的鼓励和支持!

相关推荐
chenziang11 小时前
leetcode hot 100 二叉搜索
数据结构·算法·leetcode
single5942 小时前
【c++笔试强训】(第四十五篇)
java·开发语言·数据结构·c++·算法
呆头鹅AI工作室3 小时前
基于特征工程(pca分析)、小波去噪以及数据增强,同时采用基于注意力机制的BiLSTM、随机森林、ARIMA模型进行序列数据预测
人工智能·深度学习·神经网络·算法·随机森林·回归
一勺汤4 小时前
YOLO11改进-注意力-引入自调制特征聚合模块SMFA
人工智能·深度学习·算法·yolo·目标检测·计算机视觉·目标跟踪
每天写点bug4 小时前
【golang】map遍历注意事项
开发语言·算法·golang
程序员JerrySUN4 小时前
BitBake 执行流程深度解析:从理论到实践
linux·开发语言·嵌入式硬件·算法·架构
王老师青少年编程5 小时前
gesp(二级)(16)洛谷:B4037:[GESP202409 二级] 小杨的 N 字矩阵
数据结构·c++·算法·gesp·csp·信奥赛
robin_suli5 小时前
动态规划子序列问题系列一>等差序列划分II
算法·动态规划
cxylay6 小时前
自适应滤波算法分类及详细介绍
算法·分类·自适应滤波算法·自适应滤波·主动噪声控制·anc
茶猫_6 小时前
力扣面试题 - 40 迷路的机器人 C语言解法
c语言·数据结构·算法·leetcode·机器人·深度优先