当前位置: 首页 > ai >正文

Rust: 从内存地址信息看内存布局

内存布局其实有几个:address(地址)、size(大小)、alignment(对齐位数,2 的自然数次幂,2,4,8…)。
今天主要从address来看内存的布局。

下面以Struct,Enum以默认对齐的情况下(不包括repr©等情况)分析。

一、代码


#[derive(Default)]
struct BaseStruct {field1: u8,field2: u8,field3: i32,field4: u8,field5: u8,field6: u8,field7: u8,
}struct MyStruct{field1:u8,field2:BaseStruct,field3:MyEnum,field4:i64,
}
impl MyStruct{fn default() -> Self {MyStruct {field1: 1,field2: BaseStruct::default(),field3: MyEnum::Variant1(1),field4: 2,}}
}
// Enum的内存大小:最大字段大小的2倍,下面最大为i64:8个字节enum MyEnum {Variant1(i64),Variant2(i8),Variant3(i64),Variant4(i64),
}fn main() {println!("Size of u64                   : {}", std::mem::size_of::<u64>());println!("Size of i64                   : {}", std::mem::size_of::<i64>());println!("Size of MyEnum                : {}", std::mem::size_of::<MyEnum>());println!("Align of MyEnum               : {}", std::mem::align_of::<MyEnum>());println!("Size of BaseStruct            : {}", std::mem::size_of::<BaseStruct>());println!("Align of BaseStruct           : {}", std::mem::align_of::<BaseStruct>());println!("Size of MyStruct              : {}", std::mem::size_of::<MyStruct>());println!("Align of MyStruct             : {}", std::mem::align_of::<MyStruct>());println!("-------------BaseStruct-------------");let base_struct = BaseStruct::default();println!("address of base_struct        : {}",get_ptr_address(&base_struct));println!("address of base_struct_field_1: {}",get_ptr_address(&base_struct.field1));println!("address of base_struct_field_2: {}",get_ptr_address(&base_struct.field2));println!("address of base_struct_field_3: {}",get_ptr_address(&base_struct.field3));println!("address of base_struct_field_4: {}",get_ptr_address(&base_struct.field4));println!("address of base_struct_field_5: {}",get_ptr_address(&base_struct.field5));println!("address of base_struct_field_6: {}",get_ptr_address(&base_struct.field6));println!("address of base_struct_field_7: {}",get_ptr_address(&base_struct.field7));println!("-------------MyStruct-------------");let my_struct = MyStruct::default();println!("address of my_struct          : {}",get_ptr_address(&my_struct));println!("address of my_struct_field_1  : {}",get_ptr_address(&my_struct.field1));println!("address of my_struct_field_2  : {}",get_ptr_address(&my_struct.field2));println!("address of my_struct_field_3  : {}",get_ptr_address(&my_struct.field3));println!("address of my_struct_field_4  : {}",get_ptr_address(&my_struct.field4));println!("-----------get_ptr_address_2-----------");println!("address_2 of my_struct          : {}",get_ptr_address_2(&my_struct));println!("address_2 of my_struct_field_1  : {}",get_ptr_address_2(&my_struct.field1));println!("address_2 of my_struct_field_2  : {}",get_ptr_address_2(&my_struct.field2));println!("address_2 of my_struct_field_3  : {}",get_ptr_address_2(&my_struct.field3));println!("address_2 of my_struct_field_4  : {}",get_ptr_address_2(&my_struct.field4));}fn get_ptr_address<T>(data: &T)->usize{data as *const _ as usize //会先创建一个引用
}
// 为什么不能用这个?
fn get_ptr_address_2<T>(data: &T)->usize{std::ptr::addr_of!(data) as usize //不需要创建一个引用
}

二、输出

Size of u64                   : 8
Size of i64                   : 8
Size of MyEnum                : 16
Align of MyEnum               : 8
Size of BaseStruct            : 12
Align of BaseStruct           : 4
Size of MyStruct              : 40
Align of MyStruct             : 8
-------------BaseStruct-------------
address of base_struct        : 490357126640
address of base_struct_field_1: 490357126644
address of base_struct_field_2: 490357126645
address of base_struct_field_3: 490357126640
address of base_struct_field_4: 490357126646
address of base_struct_field_5: 490357126647
address of base_struct_field_6: 490357126648
address of base_struct_field_7: 490357126649
-------------MyStruct-------------
address of my_struct          : 490357126600
address of my_struct_field_1  : 490357126636
address of my_struct_field_2  : 490357126624  // basestruct
address of my_struct_field_3  : 490357126600  // myenum
address of my_struct_field_4  : 490357126616
-----------get_ptr_address_2-----------
address_2 of my_struct          : 490357126528
address_2 of my_struct_field_1  : 490357126528
address_2 of my_struct_field_2  : 490357126528
address_2 of my_struct_field_3  : 490357126528
address_2 of my_struct_field_4  : 490357126528

三、问题

可以对照一下address的顺序,来看一下各个field以及对应Struct、Enum的大小。

1、为什么BaseStruct的大小并不是field的起始地址到field的最后地址?

BaseStruct的真实size是12个字节。但起始address起始间隔目前只看到9。为什么?

从地址信息可以看出,
(1)field3(i32),重新布局后,已经放在前面,并不是从field1开始。地址是从490357126640->490357126644:占了4个字节。
(2)接下来是field1,field2,field4,field5,依次占了1个字节。
(3)再接下来是field6,field7,各占1个字节。
因为在进行内存布局优化时,已经按4+4+4的格局进行优化,这里面4就是BaseStruct alignment。

在最后4个字节中,field6,field7已经用掉了2个,还有2个空的(alignment padding)。因此是4+4+2+2=12。

其实:BaseStruct如果没有field7,或者说,再加一个field8(u8),其size均是12个字节!

这个在MyStruct中各field的地址信息,可以更真实显示BaseStruct(field2)的大小(即上下间隔)。即490357126624 ->490357126636(注:每次运行不一样)间隔为12。

当然,MyStruct也是一样,不能把field首地址和未地址相减得到其占用大小(计算得到36个字节,并不是40个字节!)。它的alignment是8。

因此需要注意的是:最后一个,是有alignment的。有些是只有部分占用。因此不能简单通过首地址和末地址相减来获得这个大小。

2、为什么add_of!在这儿不能用?

add_of宏生成了同样的地址。

http://www.xdnf.cn/news/782.html

相关文章:

  • OpenCV 图形API(44)颜色空间转换-----将图像从 BGR 色彩空间转换为 RGB 色彩空间函数BGR2RGB()
  • XMC4800 芯片深度解读:架构、特性、应用与开发指南
  • OpenCV中的图像旋转方法详解
  • 特征选择与类不平衡处理
  • aws服务--S3介绍使用代码集成
  • Missashe考研日记-day23
  • 在Ubuntu下用Chrony做主从机时间同步
  • 栈和字符串,力扣.43.字符串相乘力扣1047.删除字符串中的所有相邻重复项力扣.844比较含退格的字符串力扣227.基本计算器II
  • 《马尼拉》桌游期望计算器
  • Ubuntu下展锐刷机工具spd_dump使用说明
  • Python3网络爬虫开发--爬虫基础
  • Java 设计模式心法之第4篇 - 单例 (Singleton) 的正确打开方式与避坑指南
  • 每天学一个 Linux 命令(30):cut
  • 【React】搜索时高亮被搜索选中的文案
  • 大数据系列 | 详解基于Zookeeper或ClickHouse Keeper的ClickHouse集群部署--完结
  • TensorFlow和PyTorch学习原理解析
  • 掌握常见 HTTP 方法:GET、POST、PUT 到 CONNECT 全面梳理
  • FreeRTos学习记录--2.内存管理
  • 华为云获取IAM用户Token的方式及适用分析
  • 潞晨科技将暂停DeepSeek API服务,AI大模型技术红利普惠化与市场竞争白热化叠加,内卷恶果,开始显现!
  • 在线查看【免费】 dcm、drawio,dcm wps文件格式网站
  • Spring Boot集成Keycloak
  • 颠覆传统!毫秒级响应的跨平台文件同步革命,远程访问如本地操作般丝滑
  • 从“堆料竞赛”到“体验深耕”,X200 Ultra和X200s打响手机价值升维战
  • 【锂电池容量特征提取】NASA数据集锂电池容量特征提取(Matlab完整源码)
  • Java中 关于编译(Compilation)、类加载(Class Loading) 和 运行(Execution)的详细区别解析
  • Linux网络编程 多进程UDP聊天室:共享内存与多进程间通信实战解析
  • 四元数转旋转矩阵
  • 极狐GitLab CEO 柳钢受邀出席 2025 全球机器学习技术大会
  • Halcon应用:相机标定之应用