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

news2025/7/16 16:22:34

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

说明:下面以Struct,Enum以默认对齐的情况下(不包括C对齐即#[repr( C )]、 紧凑对齐 #[repr(packed)]、自定义对齐 #[repr(align(n))] 等情况)进行分析。

一、代码


#[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的内存大小:最大字段大小size+8个字节,下面最大为i64:8个字节 +8 =16

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!在这儿不能用?

fn get_ptr_address_2<T>(data: &T)->usize{
    std::ptr::addr_of!(data) as usize //不需要创建一个引用
}

add_of宏生成了同样的地址。

只需要进行下面的修改就可以了。add_of宏不需要是对象的引用,直接用对象本身,不用担心会消费掉所有权。

println!("address_2 of my_struct          : {}",std::ptr::addr_of!(my_struct) as usize);
println!("address_2 of my_struct_field_1  : {}",std::ptr::addr_of!(my_struct.field1) as usize);
println!("address_2 of my_struct_field_2  : {}",std::ptr::addr_of!(my_struct.field2) as usize);
println!("address_2 of my_struct_field_3  : {}",std::ptr::addr_of!(my_struct.field3) as usize);
println!("address_2 of my_struct_field_4  : {}",std::ptr::addr_of!(my_struct.field4) as usize);

上面的修改和

fn get_ptr_address<T>(data: &T)->usize{
    data as *const _ as usize //会先创建一个引用
}

效果一样。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2341186.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Dv3Admin】从零搭建Git项目安装·配置·初始化

项目采用 Django 与 Vue3 技术栈构建&#xff0c;具备强大的后端扩展能力与现代前端交互体验。完整实现了权限管理、任务队列、WebSocket 通信、系统配置等功能&#xff0c;适用于构建中后台管理系统与多租户平台。 本文章内容涵盖环境搭建、虚拟环境配置、前后端部署、项目结…

P3416-图论-法1.BFS / 法2.Floyd

这道题虽然标签有floyd但是直接bfs也能过 其实事实证明还是bfs快&#xff0c;因为bfs只需要遍历特定的点&#xff0c;但是floyd需要考虑遍历所有可能的中介点 法1.BFS 用字典存储每个点所能普及的范围&#xff0c;然后用对每个点bfs进行拓展 nint(input())temp[]#xmax0;yma…

极狐GitLab 议题和史诗创建的速率限制如何设置?

极狐GitLab 是 GitLab 在中国的发行版&#xff0c;关于中文参考文档和资料有&#xff1a; 极狐GitLab 中文文档极狐GitLab 中文论坛极狐GitLab 官网 议题和史诗创建的速率限制 (BASIC SELF) 速率限制是为了控制新史诗和议题的创建速度。例如&#xff0c;如果您将限制设置为 …

提交到Gitee仓库

文章目录 注册配置公钥创建空白的码云仓库把本地项目上传到码云对应的空白仓库中 注册 注册并激活码云账号&#xff08; 注册页面地址&#xff1a;https://gitee.com/signup &#xff09; 可以在自己C盘/用户/用户名/.ssh 可以看到 有id_rsa.pub 以前在GitHub注册时搞过&…

oracle中错误总结

oracle中给表起别名不能用as&#xff0c;用as报错 在 Oracle 数据库中&#xff0c;​​WITH 子句&#xff08;即 CTE&#xff0c;公共表表达式&#xff09;允许后续定义的子查询引用前面已经定义的 CTE​​&#xff0c;但 ​​前面的 CTE 无法引用后面的 CTE​​。这种设计类似…

纽约大学具身智能体在城市空间中的视觉导航之旅!CityWalker:从海量网络视频中学习城市导航

作者&#xff1a;Xinhao Liu, Jintong Li, Yicheng Jiang, Niranjan Sujay, Zhicheng Yang, Juexiao Zhang, John Abanes, Jing Zhang, Chen Feng单位&#xff1a;纽约大学论文标题&#xff1a;CityWalker: Learning Embodied Urban Navigation from Web-Scale Videos论文链接&…

OpenCV颜色变换cvtColor

OpenCV计算机视觉开发实践&#xff1a;基于Qt C - 商品搜索 - 京东 颜色变换是imgproc模块中一个常用的功能。我们生活中看到的大多数彩色图片都是RGB类型的&#xff0c;但是在进行图像处理时需要用到灰度图、二值图、HSV&#xff08;六角锥体模型&#xff0c;这个模型中颜色的…

Manus技术架构、实现内幕及分布式智能体项目实战

Manus技术架构、实现内幕及分布式智能体项目实战 模块一&#xff1a; 剖析Manus分布式多智能体全生命周期、九大核心模块及MCP协议&#xff0c;构建低幻觉、高效且具备动态失败处理能力的Manus系统。 模块二&#xff1a; 解析Manus大模型Agent操作电脑的原理与关键API&#xf…

下载油管视频 - yt-dlp

文章目录 1. yt-dlp与you-get介绍1.1 主要功能对比1.2 使用场景1.3 安装 2. 基本命令介绍2.1 默认下载视频2.2 指定画质和格式规则2.3 下载播放列表2.4 备注 3. 参考资料 之前只使用you-get下载b站视频&#xff0c;当时了解you-get也可下载油管视频&#xff0c;但之前无此需求&…

济南通过首个备案生活服务大模型,打造行业新标杆

近日&#xff0c;一则振奋人心的消息在人工智能领域传开&#xff1a;济南本土企业丽阳神州智能科技有限公司自主研发的 “丽阳雨露” 大模型成功通过国家网信办的备案。这一成果不仅是济南企业在科技创新道路上的重大突破&#xff0c;更标志着我国在生活服务领域的人工智能应用…

第6次课 贪心算法 A

向日葵朝着太阳转动&#xff0c;时刻追求自身成长的最大可能。 贪心策略在一轮轮的简单选择中&#xff0c;逐步导向最佳答案。 课堂学习 引入 贪心算法&#xff08;英语&#xff1a;greedy algorithm&#xff09;&#xff0c;是用计算机来模拟一个「贪心」的人做出决策的过程…

Hexo+Github+gitee图床零成本搭建自己的专属博客

一个详细、完善的 Hexo 博客部署教程&#xff0c;不仅涵盖了基本的安装、配置、生成与部署步骤&#xff0c;还增加了常见问题的解决、主题设置、图片上传等 在开始之前可以看看我最终搭建出来的成果&#xff1a;https://liangjh.blog 1.安装git和nodejs 在Windows上使用Git&a…

数字信号处理技术架构与功能演进

数字信号处理&#xff08;DSP&#xff09;是通过数字运算实现信号分析、变换、滤波及调制解调的技术领域&#xff0c;其发展过程与技术应用如下&#xff1a; 一、定义与核心功能 技术定义&#xff1a;通过算法将模拟信号转换为数字形式进行处理&#xff0c;具有高精度、可编程…

深入理解 Android Handler

一、引言 Handler 在安卓中的地位是不言而喻的&#xff0c;几乎维系着整个安卓程序运行的生命周期&#xff0c;但是这么重要的一个东西&#xff0c;我们真的了解它吗&#xff1f;下面跟随着我的脚步&#xff0c;慢慢揭开Hanler的神秘面纱吧&#xff01; 本文将介绍Handler 的运…

C++ 什么是隐式类型转换,什么是显式类型转换

在 C 中&#xff0c;​​类型转换​​是将一种数据类型的值转换为另一种数据类型的过程&#xff0c;分为 ​​隐式类型转换​​&#xff08;由编译器自动完成&#xff09;和 ​​显式类型转换​​&#xff08;由程序员手动指定&#xff09;。以下是它们的区别和示例&#xff1a…

NVIDIA 自动驾驶技术见解

前言 参与 NVIDIA自动驾驶开发者实验室 活动&#xff0c;以及解读了 NVIDIA 安全报告 自动驾驶 白皮书&#xff0c;本文是我的一些思考和见解。自动驾驶技术的目标是为了改善道理安全、减少交通堵塞&#xff0c;重塑更安全、高效、包容的交通生态。在这一领域&#xff0c;NVI…

【Flask】Explore-Flask:早期 Flask 生态的实用指南

开源项目&#xff1a;explore-flask/README.rst at master rpicard/explore-flask (github.com) 一、Coding conventions Summary Try to follow the coding style conventions laid out in PEP 8. Try to document your app with docstrings as defined in PEP 257. def…

【论文阅读21】-PSOSVM-CNN-GRU-Attention-滑坡预测(2024-12)

这篇论文主要提出并验证了一种新型的混合智能模型&#xff08;PSOSVM-CNN-GRU-Attention&#xff09;&#xff0c;用于准确预测滑坡的点位移&#xff0c;并构建可靠的位移预测区间。通过对Baishuihe滑坡和Shuping滑坡的案例分析&#xff0c;展示了该模型的出色性能。 [1] Zai D…

蓝牙 6.0 发布,解锁无线科技新可能

在5G和Wi-Fi 7高速发展的时代&#xff0c;蓝牙技术始终以独特优势深度融入日常生活。从无线耳机到智能家居&#xff0c;它凭借低功耗、高兼容的特性&#xff0c;悄然连接各类智能设备&#xff0c;打造无缝的数字生活体验。无论是聆听音乐、智能门禁还是健康监测&#xff0c;蓝牙…

EasyCVR视频智能分析平台助力智慧园区:全场景视频监控摄像头融合解决方案

一、方案背景 在智慧园区建设的浪潮下&#xff0c;设备融合、数据整合与智能联动已成为核心诉求。视频监控作为智慧园区的“视觉中枢”&#xff0c;其高效整合直接影响园区的管理效能与安全水平。然而&#xff0c;园区内繁杂的视频监控设备生态——不同品牌、型号、制式的摄像…