我知道Rust结构中的字段会自动重新排序以节省内存(除非例如。
#[repr(C)]
被指定)。
我的假设是,枚举也是如此。
今天我创建了一个简单的助手类型(示例的语义无关紧要,这是关于内存布局的):
pub enum LazyRwLockGuardVersionA<'a, T> {
Unlocked(&'a RwLock<T>),
Read {
lock: &'a RwLock<T>, // still neccessary for promoting to write lock
guard: RwLockReadGuard<'a, T>,
},
Write(RwLockWriteGuard<'a, T>),
}
而原始读/写保护使用
16
字节,此类型使用
32
.
为了让编译器使用利基优化,我尝试了这个版本:
pub enum LazyRwLockWriteGuard<'a, T> {
Unlocked(&'a RwLock<T>),
Write(RwLockWriteGuard<'a, T>),
}
pub enum LazyRwLockGuardVersionB<'a, T> {
Read {
guard: RwLockReadGuard<'a, T>,
lock: &'a RwLock<T>,
},
NonRead(LazyRwLockWriteGuard<'a, T>),
}
这成功地将内存使用率降低到
24
字节。
然而,我注意到了一些奇怪的事情:
反转中字段的顺序时
Read
变种
pub enum LazyRwLockGuardVersionC<'a, T> {
Read {
lock: &'a RwLock<T>, // order of fields reversed
guard: RwLockReadGuard<'a, T>,
},
NonRead(LazyRwLockWriteGuard<'a, T>),
}
这种类型突然使用
32
字节。
我的Rust版本是1.77,这里有一个godbolt repro:
https://godbolt.org/z/svE5v6Tr8
-
是规范不允许对枚举字段进行重新排序,还是编译器在这里只是“懒惰”?
-
编译器当前使用的算法是否有粗略的直觉
用于布局枚举,这样我就可以理解这个结果,并防止将来意外地对我的代码进行悲观化?