阅读量:0
可以使用std::mem:size_of
获取类型大小:
use std::mem::size_of; struct Journal(String, u32); trait Summary {} impl Summary for Journal {} fn main() { println!("普通结构体相关:"); println!("{}", size_of::<&Journal>()); println!("{}", size_of::<Box<Journal>>()); println!("特征对象相关:"); println!("{}", size_of::<Box<dyn Summary>>()); println!("{}", size_of::<&dyn Summary>()); println!("{}", size_of::<&mut dyn Summary>()); println!("{}", size_of::<*const dyn Summary>()); println!("{}", size_of::<*mut dyn Summary>()); println!("切片相关:"); println!("{}", size_of::<&str>()); println!("{}", size_of::<&[i32]>()); println!("{}", size_of::<&[i32; 100]>()); println!("集合相关:"); println!("{}", size_of::<[i32; 100]>()); println!("{}", size_of::<Vec<i32>>()); println!("{}", size_of::<String>()); }
输出
普通结构体相关: 8 8 特征对象相关: 16 16 16 16 16 切片相关: 16 16 8 集合相关: 400 24 24
原因分析
Rust中,一个普通指针的大小为usize,与计算机CPU字长相等,对64位计算机来说usize=64/8=8字节
- 对普通结构体来说,其引用/Box智能指针所占大小为
usize
,指示在内存中的起始位置即可,因为普通结构体编译时大小确定,运行时存放在栈上 - 特征对象非常特殊,其引用/Box智能指针/裸指针占的大小均为
2*usize
- 这是因为特征对象编译时大小不确定,因此需要在运行时动态获知对象实例以及特征方法在内存中的位置,因此需要两个指针,分别指向它们
- 对切片类型:
&str
所占空间为2*usize
,所引用字符串可能来自于堆内存/全局数据区,&str指示了所引用数据的起始位置和长度&[i32]
与&str
类似(&str
是对&[u8]
的封装),所占空间为2*usize
,指示了所引用字符串在堆内存/栈内存中的起始位置和长度&[i32; N]
仅占一个usize
,因为[i32; N]
编译时大小已知,存放在栈上,&[i32; N]
不需要像&[i32]
那样额外记录长度
- 对集合相关:
[i32; 100]
编译时大小已知,存放在栈上,内存大小为4*100=400个字节Vec
动态数组的数据存放在堆上,Vec
类型占三个usize的长度,分别指示数组在堆中的起始位置,数组长度以及数组当前的最大容量String
是对Vec<u8>
的封装,其数据存放在堆上,String
类型占三个usize
的长度,分别指示字符串在堆中的起始位置,字符串长度以及字符串当前的最大长度
其实,Vec
和String
的本质都是智能指针,它们的大小都是固定的(大小不固定也没法通过编译啊),运行时存放在栈上。但是它们所包裹数据的长度是可变的,存放在堆上。它们的本质是通过存放在栈上的指针访问堆内存,来操作堆上包裹的数据。
综上所述,智能指针/引用所占内存大小是固定的,但是其指向的数据大小未必固定。对于所占内存固定已知的数据类型,运行时会把它们放在栈上,对于所占内存不固定的数据类型,运行时会把它们放在堆上,然后可以通过存放在栈上的指针来操作堆上的数据。