为什么Box <[T]>在内存中需要16个字节,但是引用的切片仅需要8个字节? (在x64机器上)

时间:2019-04-23 15:01:19

标签: rust

考虑:

fn main() {
    // Prints 8, 8, 16
    println!(
        "{}, {}, {}",
        std::mem::size_of::<Box<i8>>(),
        std::mem::size_of::<Box<&[i8]>>(),
        std::mem::size_of::<Box<[i8]>>(),
    );
}

为什么拥有的切片占用16个字节,而引用的切片仅占用8个字节?

2 个答案:

答案 0 :(得分:17)

Box<T>基本上是*const T(实际上是围绕Unique<T>的新类型,它本身就是带有NonNull<T>的{​​{1}}(对于dropck) ,但为简单起见,请坚持使用PhantomData<T>

Rust中的指针通常具有与*const T相同的大小,除非size_of::<usize>()dynamically sized type(DST)。当前,T的大小为Box<DST>(在撰写本文时,确切的表示形式并不稳定)。指向DST的指针称为2 * size_of::<usize>()

当前,DST有两种:切片和特征。切片的FatPtr定义如下:

FatPtr

注意:对于特征指针,#[repr(C)] struct FatPtr<T> { data: *const T, len: usize, } 被指向len的指针代替。

有了这些信息,您的问题就可以得到答案:

  • vtableBox<i8>是一种大小类型=>与i8 =>基本上相同,大小为8个字节(指针宽度为64位)
  • *const i8Box<[i8]>是DST =>与[i8] =>基本上相同,大小为16个字节(指针宽度为64位)
  • FatPtr<i8>Box<&[i8]> 不是 DST。它基本上与&[i8] => 8字节大小(指针宽度为64位)相同

答案 1 :(得分:3)

引用的大小取决于引用类型的“大小”:

  • 对大小类型的引用是指向内存地址的单个指针。
  • 对未定义大小类型的引用是指向存储器和指向数据的大小的指针。这就是所谓的fat pointer

    #[repr(C)]
    struct FatPtr<T> {
        data: *const T,
        len: usize,
    }
    

Box是一种特殊的指向堆的指针,但它仍然是一个指针。

知道这一点,您就会了解:

  • Box<i8>是8个字节,因为i8的大小,
  • Box<&[i8]>为8个字节,因为引用的大小已确定,
  • Box<[i8]>为16字节,因为切片未调整大小。