Rust의 enum에 크기가 다른 형태를 열거하면 메모리 사이즈 효율이 나쁘다는 이야기

7581 단어 Rust
예를 들면, 이하와 같은 enum 를 정의했을 경우, 그 사이즈는 16 바이트가 됩니다.
enum Hoge {
    Char(i8),
    Short(i16),
    Long(i32),
    LongLong(i64),
}

let size = mem::size_of::<Hoge>();
assert_eq!(size, 16);
Hoge 의 데이터 구조가 무엇인지 확인합니다.
let long = Hoge::Long(65536);
let slice = unsafe { mem::transmute::<Hoge, [u8; 16]>(long) };
slice.iter()
    .enumerate()
    .for_each(|(i, v)| println!("index: {}, value: {:x}", i, v));
$ cargo run
index: 0, value: 2   // tag       enum の何番目の識別子か
index: 1, value: 44  // _padding0 ここから
index: 2, value: ed  //           ↓
index: 3, value: 3   //           ここまで
index: 4, value: 0   // data      ここから
index: 5, value: 0   //           ↓
index: 6, value: 1   //           ↓
index: 7, value: 0   //           ここまで
index: 8, value: 0   // _padding1 ここから
index: 9, value: 0   //           ↓
index: 10, value: 0  //           ↓
index: 11, value: 0  //           ↓
index: 12, value: 0  //           ↓
index: 13, value: 0  //           ↓
index: 14, value: 0  //           ↓
index: 15, value: 0  //           ここまで

enum Hoge 열거자의 데이터 구조를 가상적인 구조체로서 나타내면,
struct EnumHoge {
    tag: u8,
    _padding0: [u8; ?],
    data: i8 | i16 | i32 | i64,
    _padding1: [u8; ?],
}

같은 느낌이 되고 있습니다.
_padding0 의 크기는 data 가 메모리 정렬 경계를 넘지 않도록 data 의 크기에 따라 달라집니다. Char_padding 는 0. Short 는 1. Long 는 3. LongLong 그렇다면 7입니다. _padding1 에 16바이트의 나머지가 채워집니다.

여기서 새로운 의문이. 만약 열거자의 수가 256 를 넘으면 어떻게 되는 것인가? 즉 tagu8 가 오버플로우 하면 어떻게 되는 것인가? (현실적으로는 우선 있을 수 없다고 생각합니다만)

실제로 해봤다.
enum Piyo {
    LongLong0(i64),
    LongLong1(i64),
    LongLong2(i64),
    LongLong3(i64),
    // 省略
    LongLong65534(i64),
    LongLong65535(i64),
    Char(i8),
    Short(i16),
    Long(i32),
}

VSCode에서 ↑를 쓰면 메모리가 끊어지고 스왑이 4GiB 이상으로 PC가 고정되었습니다.
어쩌면 tag의 크기가 u32로 바뀔 것입니다.

이야기가 조금 탈선했습니다. 메모리 크기 효율이 나쁘다는 이야기로 되돌리자.

예를 들어 ↓ 이런 식으로 HogeVec 에 넣으면 실제 데이터로서의 크기는 15바이트인데 padding 이 있기 때문에 64바이트도 사용해 버린다는 것입니다.
enum Hoge {
    Char(i8),      // 1 バイト
    Short(i16),    // 2 バイト
    Long(i32),     // 4 バイト
    LongLong(i64), // 8 バイト
}
// 1 + 2 + 4 + 8 = 15 バイト!

use Hoge::*;
let v = vec![Char(0), Short(1), Long(2), LongLong(3)];
// v の大きさは 16 * 4 = 64 バイト!

끝.

좋은 웹페이지 즐겨찾기