Rust 內存佈局
整型, 浮點型, struct,vec!,enum
本文是對 Rust 內存佈局 [1] 的學習與記錄
struct A {
a: i64,
b: u64,
}
struct B {
a: i32,
b: u64,
}
struct C {
a: i64,
b: u64,
c: i32,
}
struct D {
a: i32,
b: u64,
c: i32,
d: u64,
}
fn main() {
println!("i32類型佔的內存空間爲:{}字節", std::mem::size_of::<i32>());
println!("i64類型佔的內存空間爲:{}字節", std::mem::size_of::<i64>());
println!(
"[i64;4]佔的內存空間爲:{}字節",
std::mem::size_of::<[i64; 4]>()
);
println!("結構體A佔的內存空間爲:{}字節", std::mem::size_of::<A>());
println!("結構體B佔的內存空間爲:{}字節", std::mem::size_of::<B>());
println!("結構體C佔的內存空間爲:{}字節", std::mem::size_of::<C>());
println!("結構體D佔的內存空間爲:{}字節", std::mem::size_of::<D>());
}
輸出
i32類型佔的內存空間爲:4字節
i64類型佔的內存空間爲:8字節
[i64;4]佔的內存空間爲:32字節
結構體A佔的內存空間爲:16字節
結構體B佔的內存空間爲:16字節
結構體C佔的內存空間爲:24字節
結構體D佔的內存空間爲:24字節
沒啥好說的, 和 Go 一樣, struct 會存在內存對齊 / 內存填充 (8 字節對齊)
D 是因爲編譯器會優化內存佈局, 字段順序重排
Rust 中的 Vec! 和 Go 中的 slice 差不多, 都是佔 24Byte, 三個字段
struct SimpleVec<T> {
len: usize, // 8
capacity: usize, //8
data: *mut T, //8
}
fn main() {
println!(
"Vec!類型佔的內存空間爲:{}字節",
std::mem::size_of::<SimpleVec<i32>>()
);
println!(
"Option<i64>類型佔的內存空間爲:{}字節",
std::mem::size_of::<Option<i64>>()
);
}
Vec!類型佔的內存空間爲:24字節
Option<i64>類型佔的內存空間爲:16字節
但是對於 enum 類型,
會有一個 tag 字段, uint64, 來標記變體, 是 None 值還是 Some 值
struct Option {
uint64 tag; // 佔8字節 Some None
i64; //實際存放的數據
}
struct SimpleVec<T> {
len: usize, // 8
capacity: usize, //8
data: *mut T, //8
}
enum Data {
// tag,uint64,8字節
I32(i32), // 4字節,但需內存對齊到8字節?
F64(f64), // 8字節
Bytes(SimpleVec<u8>), // 24字節
}
fn main() {
println!(
"Data這個Enum類型佔的內存空間爲:{}字節",
std::mem::size_of::<Data>()
);
}
輸出爲:
Data這個Enum類型佔的內存空間爲:32字節
Rust 的 enum 類似 C++ std::variant 的實現 (大致是用 union 實現的)
union 的內存大小是其成員中最大的那個成員的大小,
類似的, 對於 Data 這個 Enum 類型, 會選擇最大的那個成員的大小
所以 24+tag 的 8 字節, 最終爲 32 字節 (tag 在這裏就用來標識其爲 i32, 還是 f64, 或者是 Vec)
嵌套的枚舉:
struct SimpleVec<T> {
len: usize, // 8
capacity: usize, //8
data: *mut T, //8
}
enum Data {
// tag,uint64,8字節
I32(i32), // 4字節,但需內存對齊到8字節?
F64(f64), // 8字節
Bytes(SimpleVec<u8>), // 24字節
}
type OptData = Option<Data>;
fn main() {
println!(
"OptData這個Option類型佔的內存空間爲:{}字節",
std::mem::size_of::<OptData>()
);
}
輸出:
OptData這個Option類型佔的內存空間爲:32字節
因爲編譯器會對嵌套的枚舉類型進行優化, 會將其 tag 展開, 把多個 tag 合在一起了, 類似下面:
展開變成一個枚舉 (None 是 uint64, 能標識非常多信息)
type OptData = Option<Data>;
enum Option {
Some,
None,
}
enum OptData_ {
I32(i32);
F64(f64);
Bytes(SimpleVec<u8>),
None
}
元組 tuple
rust 中的元組大小固定嗎?
在 Rust 中, 元組的大小是固定的。這裏解釋一下元組大小固定的含義:
-
元組中的元素類型和數量在編譯期就已經確定, 不能在運行期修改。
-
編譯器會根據元組中元素的類型, 預先分配足夠的內存用於存儲這些元素。
-
元組的內存佈局和大小也在編譯期就確定下來了, 運行期不會改變。
-
嘗試創建包含不同類型或數量元素的元組, 是編譯時錯誤。
舉個例子:
let tuple = (1, 2.0, "three");
這裏元組包含一個 i32, 一個 f64 和一個字符串。編譯器會預先知道:
-
元組元素類型爲 i32, f64, &str
-
i32 佔用 4 字節, f64 佔用 8 字節,&str 佔據一個指針的空間
-
所以該元組佔用的內存大小爲 4 + 8 + 8 = 20 字節
這 20 字節的內存在編譯時就已分配, 運行期不會改變。
如果後續試圖給這個元組添加或減少元素, 編譯都會報錯。
所以說, 元組的大小和內容是固定的, 這是 Rust 實現方式的一部分。
更多可參考 Rust 數據內存佈局 [2]
參考資料
[1]
Rust 內存佈局: https://www.bilibili.com/video/BV1Bm4y1c71r
[2]
Rust 數據內存佈局: https://blog.csdn.net/techdashen/article/details/120257323
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/Hhzr8e9u8VJ7kXHSr32QPw