Consider:
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]>>(),
);
}
Why do owned slices take 16 bytes, but referenced slices take only 8?
All values in Rust are stack allocated by default. Values can be boxed (allocated on the heap) by creating a Box<T> . A box is a smart pointer to a heap allocated value of type T . When a box goes out of scope, its destructor is called, the inner object is destroyed, and the memory on the heap is freed.
Because a Box<T> is a pointer, Rust always knows how much space a Box<T> needs: a pointer's size doesn't change based on the amount of data it's pointing to.
Box<T>
is basically *const T
(Actually it's a newtype around Unique<T>
, which itself is a NonNull<T>
with PhantomData<T>
(for dropck), but let's stick to *const T
for simplicity).
A pointer in Rust normally has the same size as size_of::<usize>()
except when T
is a dynamically sized type (DST). Currently, a Box<DST>
is 2 * size_of::<usize>()
in size (the exact representation is not stable at the time of writing). A pointer to a DST is called FatPtr
.
Currently, there are two kinds of DSTs: Slices and traits. A FatPtr
to a slice is defined like this:
#[repr(C)]
struct FatPtr<T> {
data: *const T,
len: usize,
}
Note: For a trait pointer, len
is replaced by a pointer to the vtable
.
With those information, your question can be answered:
Box<i8>
: i8
is a sized type => basically the same as *const i8
=> 8 bytes in size (with 64 bit pointer width)Box<[i8]>
: [i8]
is a DST => basically the same as FatPtr<i8>
=> 16 bytes in size (with 64 bit pointer width)Box<&[i8]>
: &[i8]
is not a DST. It's basically the same as *const FatPtr<i8>
=> 8 bytes in size (with 64 bit pointer width)The size of a reference depends on the "sizedness" of the referenced type:
A reference to an unsized type is a pointer to the memory and the size of the pointed datum. That's what is called a fat pointer:
#[repr(C)]
struct FatPtr<T> {
data: *const T,
len: usize,
}
A Box
is a special kind of pointer that points to the heap, but it is still a pointer.
Knowing that, you understand that:
Box<i8>
is 8 bytes because i8
is sized,Box<&[i8]>
is 8 bytes because a reference is sized,Box<[i8]>
is 16 bytes because a slice is unsized.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With