Rc 比 Box 多占多少内存?计数器放在哪里?Weak 为什么能在数据销毁后继续存在?这篇用 size_of、全局分配器的 Layout 记录、直接读堆内存和 Drop 计数,把 Box / Rc / Arc 的内存布局量出来。
编译:成功
运行(退出码 0):
Box<u64> 8 Rc<u64> 8 Arc<u64> 8 &u64 8
Box<dyn Debug> 16 Rc<dyn Debug> 16 Arc<dyn Debug> 16
Box<[u8]> 16 Rc<str> 16 Arc<[u32]> 16 Box<str> 16
Option<Box<u64>> 8 Option<Rc<u64>> 8 Option<Arc<u64>> 8
Vec<u8> 24 String 24Box 的基础见Box<T> 与堆分配。
编译:成功
运行(退出码 0):
Box<u64>(8 字节的数据): 分配 8 字节,对齐 8,1 次分配
Rc<u64>: 分配 24 字节,对齐 8,1 次分配(8 字节数据 + 16 字节的计数器)
Arc<u64>: 分配 24 字节,对齐 8,1 次分配
Rc<[u8; 100]>: 分配 120 字节(16 字节计数器 + 100 字节数据 = 116,按对齐 8 补到 120)
Rc<str> from "hello": 分配 24 字节(16 字节计数器 + 5 字节字符串 = 21,补到 24),1 次分配(字符串与计数器在同一块)
Box<()>(零大小类型): 0 次分配 编译:成功
运行(退出码 0):
Rc::new: (strong, weak) = (1, 1)(weak 起始为 1:所有 strong 引用合起来持有的那一个隐式 weak)
clone 一次: (2, 1) strong_count() = 2 weak_count() = 0
downgrade: (2, 2) strong_count() = 2 weak_count() = 1
drop 两个 Rc: Weak::upgrade() = None(数据已被 drop,但内存块还在,因为还有 Weak)
Arc 同样: (2, 1) strong_count = 2 编译:成功
运行(退出码 0):
(先打印一行,让 stdout 的缓冲区先分配好,以免干扰计数)
(Noisy::drop 被调用:数据被销毁)
创建 Rc + Weak 后: 存活的堆块 +1
drop 最后一个强引用后: 存活的堆块 +1(上面打印的 Noisy::drop 说明数据已销毁,内存块仍在,因为 Weak 还指着它)
drop 最后一个 Weak 后: 存活的堆块 +0