Rust: 從內存地址信息看內存布局

內存布局其實有幾個: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 =16enum 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.pswp.cn/bicheng/78095.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/78095.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/78095.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

每日一題算法——兩個數組的交集

兩個數組的交集 力扣題目鏈接 我的解法&#xff1a;利用數組下標。 缺點&#xff1a;當取值范圍很大時&#xff0c;浪費空間。 class Solution { public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {int count1[1001]{0…

c++ 互斥鎖

為練習c 線程同步&#xff0c;做了LeeCode 1114題. 按序打印&#xff1a; 給你一個類&#xff1a; public class Foo {public void first() { print("first"); }public void second() { print("second"); }public void third() { print("third"…

山東大學軟件學院創新項目實訓開發日志(20)之中醫知識問答自動生成對話標題bug修改

在原代碼中存在一個bug&#xff1a;當前對話的標題不是現有對話的用戶的第一段的前幾個字&#xff0c;而是歷史對話的第一段的前幾個字。 這是生成標題的邏輯出了錯誤&#xff1a; 當改成size()-1即可

WSL2-Ubuntu22.04下拉取Docker MongoDB鏡像并啟動

若未安裝docker可參考此教程&#xff1a;可以直接在wsl上安裝docker嗎&#xff0c;而不是安裝docker desktop&#xff1f;-CSDN博客 1. 拉取鏡像 docker pull mongo:latest 2.打開網絡加速&#xff0c;再次拉取鏡像 3.創建docker-compose.yml 進入vim編輯器后輸入i進行編輯&a…

中通 Redis 集群從 VM 遷移至 PVE:技術差異、PVE 優劣勢及應用場景深度解析

在數字化轉型浪潮下&#xff0c;企業對服務器資源的高效利用與成本控制愈發重視。近期&#xff0c;中通快遞將服務器上的 Redis 集群服務從 VM&#xff08;VMware 虛擬化技術&#xff09;遷移至 PVE&#xff08;Proxmox VE&#xff09;&#xff0c;這一技術舉措引發了行業廣泛關…

Prometheus+Grafana實時監控系統各項指標

一、監控架構設計 核心組件與數據流 Prometheus&#xff1a;時序數據采集、存儲與告警規則管理Node Exporter&#xff1a;采集主機指標&#xff08;CPU、內存、磁盤、網絡等&#xff09;數據庫Exporter&#xff1a;如 mysqld_exporter、postgres_exporterGrafana&#xff1a;…

[密碼學基礎]GMT 0029-2014簽名驗簽服務器技術規范深度解析

GMT 0029-2014簽名驗簽服務器技術規范深度解析 引言 在數字化轉型和網絡安全需求激增的背景下&#xff0c;密碼技術成為保障數據完整性與身份認證的核心手段。中國密碼管理局發布的GMT 0029-2014《簽名驗簽服務器技術規范》&#xff0c;為簽名驗簽服務器的設計、開發與部署提…

多路轉接select服務器

目錄 select函數原型 select服務器 select的缺點 前面介紹過多路轉接就是能同時等待多個文件描述符&#xff0c;這篇文章介紹一下多路轉接方案中的select的使用 select函數原型 #include <sys/select.h> int select(int nfds, fd_set *readfds, fd_set *writefds, f…

QT6 源(45):分隔條 QSplitter 允許程序的用戶修改布局,程序員使用 IDE時,就是分隔條的用戶,以及其 QSplitter 源代碼

&#xff08;1&#xff09; &#xff08;2&#xff09;本類的繼承關系如下&#xff0c;所以說分隔條屬于容器&#xff1a; &#xff08;3&#xff09;本類的屬性&#xff1a; &#xff08;4&#xff09; 這是一份 QSplitter 的舉例代碼&#xff0c;注意其構造函數時候的傳參&am…

VSCode PIO使用Jlink SWD燒錄Stm32

一、背景 PIO的編譯速度比Arduino快很多&#xff0c;同樣支持Arduino的語法。VScode的自動補全和插件也能夠幫助快速開發目前使用JLINK SWD的方式連接STM32 二、配置 在ini配置文件中&#xff0c;添加如下內容 [env:genericSTM32F103C8] platform ststm32 board genericS…

JavaScript 渲染內容爬取:Puppeteer 入門

在現代網絡應用中&#xff0c;許多網頁內容是通過 JavaScript 渲染生成的&#xff0c;傳統的爬蟲工具往往難以獲取這些動態內容。Puppeteer 作為一種強大的瀏覽器自動化工具&#xff0c;為這一問題提供了優雅的解決方案。本文將帶你入門 Puppeteer&#xff0c;介紹如何安裝、啟…

卷積神經網絡:視覺煉金術士的數學魔法

引言&#xff1a;當數學遇見視覺煉金術 在人工智能的奇幻世界里&#xff0c;卷積神經網絡&#xff08;CNN&#xff09;猶如掌握視覺奧秘的煉金術士&#xff0c;將原始像素的"鉛塊"淬煉成認知的"黃金"。這種融合數學嚴謹性與生物靈感的算法架構&#xff0c…

Android Cordova 開發 - Cordova 快速入門(Cordova 環境配置、Cordova 第一個應用程序)

一、Cordova 1、Cordova 概述 Cordova 是使用 HTML&#xff0c;CSS 和 JavaScript 構建混合移動應用程序的平臺 2、Cordova 特征 &#xff08;1&#xff09;命令行界面&#xff08;Cordova CLI&#xff09; 這是可用于啟動項目&#xff0c;構建不同平臺的進程&#xff0c;…

ubuntu18.04啟動不了修復

參考: 虛擬機里的Ubuntu18.4啟動時進入到grub rescue救援模式&#xff08;無法正常進入到系統&#xff09;&#xff0c;ls查看后只有一個硬盤和分區&#xff0c;且無法找到/boot/grub文件【已解決】_ubuntu grub rescue-CSDN博客 本人fdisk錯誤使用,導致了grub啟動不了 第一步…

SpringBoot3設置maven package直接打包成二進制可執行文件

注意事項 SpringBoot普通native打包順序clean compile spring-boot:process-aot native:compile 使用以下配置只會的打包順序clean package&#xff08;注意&#xff1a;使用此配置以后打包會有編譯后的class文件、jar包、original源文件、二進制可執行文件【Linux是無后綴的包…

【華為】防火墻雙擊熱備-之-主備模式-單外網線路

FW1和FW2的業務接口都工作在三層&#xff0c;上行連接二層交換機。上行交換機連接運營商的接入點&#xff0c;運營商為企業分配的IP地址為100.100.100.2。現在希望FW1和FW2以主備備份方式工作。正常情況下&#xff0c;流量通過FW1轉發&#xff1b;當FW1出現故障時&#xff0c;流…

MYSQL之表的操作

1. 創建表 語法: CREATE TABLE table_name ( field1 datatype, field2 datatype, field3 datatype ) character set 字符集 collate 校驗規則 engine 存儲引擎; field 表示列名, datatype 表示列的類型character set 字符集, 如果沒有指定字符集, 則以所在數據庫的字符集為…

RAG進階:Chroma開源的AI原生向量數據庫

一、Chroma 核心概念與優勢 1. 什么是 Chroma&#xff1f; Chroma 是一款開源的向量數據庫&#xff0c;專為高效存儲和檢索高維向量數據設計。其核心能力在于語義相似性搜索&#xff0c;支持文本、圖像等嵌入向量的快速匹配&#xff0c;廣泛應用于大模型上下文增強&#xff0…

店匠科技摘得 36 氪“2025 AI Partner 創新大獎”

全場景 AI 方案驅動跨境電商數智化躍遷 4 月 18 日,36 氪 2025 AI Partner 大會于上海盛大開幕。大會緊扣“Super App 來了”主題,全力探尋 AI 時代的全新變量,探索 AI 領域下一個超級應用的無限可能性。在此次大會上,跨境電商獨立站 SaaS 平臺店匠科技(Shoplazza)憑借“店匠跨…

SQL技術終極指南:從內核原理到超大規模應用

一、DDL核心應用場景與最佳實踐 1.1 表結構設計場景矩陣 業務場景核心語法要素典型實現案例電商用戶畫像JSON字段虛擬列索引CREATE TABLE users (id INT, profile JSON, AS (profile->>$.age) VIRTUAL, INDEX idx_age((profile->>$.age)))物聯網時序數據分區表壓…