Rust 中內存對齊
Rust 中內存對齊
如果你曾讀 CSAPP 一書,那你一定記得 CSAPP 中關於 C 語言內結構體內存對齊的描述。
內存對齊的背景和概念
當 CPU 對數據進行訪問時,每次都是取指定的字節數。例如每次取 4 字節,若當前數據類型爲 int, 且地址位爲 0x00-0x03, 則一次性可以取出該變量;若該變量的地址爲 0x02-0x05, 則會分別取 0x00-0x03, 0x04-0x07 兩個地址,因此會存在一定的性能消耗。
對此,可以採用內存對齊策略來優化存儲,以 C 語言結構體爲例:
struct ss {
int i;
char c;
int j;
char d;
} test = {
1,
'a',
2,
'b',
};
int main() {
printf("%lu", sizeof(test)); // 16
}
首先思考,結構體 ss
中,兩個 int 類型,兩個 char 類型,一共佔據 10 字節。
但是,由於內存對齊策略,實際存儲到內存中,char 類型需要對齊 int 類型的 4 字節,因此結構體 ss 一共佔據 16 字節。
其示例圖如下:
0x00 - 0x03 i0 i1 i2 i3 // 一個 int 變量佔據四字節
0x04 - 0x07 c0 // 一個 char 變量佔據一字節
0x08 - 0x0B j0 j1 j2 j3 // 但由於內存對齊,會對齊 int 類型的 4 字節
0x0C - 0x0F d0
以上,就是內存對齊的背景和概念。
優化 C 語言中結構體
上例中,爲了優化運行耗時,內存對齊策略將原本只有 10 字節的結構體擴展到了 16 字節,此時,可以修改結構體內變量的排序來優化內存:
struct ss2 {
int i;
char c;
char d;
int j;
} test2 = {
1,
'a',
'b',
2,
};
int main() {
printf("%lu", sizeof(test2)); // 12
}
結構體 ss2 生成的變量內存佔據 12 字節,這是因爲,char 類型的變量 d 使用了變量 c 中未使用的部分,其示例如下:
0x00 - 0x03 i0 i1 i2 i3
0x04 - 0x07 c0 d0
0x08 - 0x0B j0 j1 j2 j3
Rust 中的內存對齊
在 Rust 中,也有結構體的概念,但是在內存對齊的處理上與 C 語言有所不同,例如:
struct A {
i: i32,
u1: u8,
j: i32,
u2: u8,
}
fn main() {
println!("{:?}", std::mem::size_of::<A>()); // 12
}
在 Rust 中, char 類型佔據 4 個字符,因此使用 u8 代替 char.
上述代碼中,i32 類型佔據 4 個字節,u8 類型佔據 1 個字節,兩個 i32 和兩個 u8 一共佔據 10 個字節。
#[repr(C)]
struct B {
i: i32,
u1: u8,
j: i32,
u2: u8,
}
fn main() {
println!("{:?}", std::mem::size_of::<B>()); // 16
}
感悟
這個示例並無太大難度,但是可以留下一些思考:在實際開發中,得益於高度完善的編譯器、解釋器等工具,開發者可以將更多的精力放到對工程代碼的可讀性、正確性上,而沒有必要_過多_擔心某語句、某變量、某聲明是否會對運行時間帶來影響。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/7kjiBDkruPWgqmDfg7T--g