整型,浮點型,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]
參考資料
Rust內存布局: https://www.bilibili.com/video/BV1Bm4y1c71r
[2]Rust 數據內存布局: https://blog.csdn.NET/techdashen/article/details/120257323