【发布时间】:2020-04-13 11:37:02
【问题描述】:
如果我们看下面的代码(playground link):
use std::cell::RefCell;
use std::rc::Rc;
struct Person {
name: String,
parent: Option<Rc<RefCell<Person>>>,
child: Option<Rc<RefCell<Person>>>,
}
impl Drop for Person {
fn drop(&mut self) {
println!("dropping {}", &self.name);
}
}
pub fn main() {
let anakin = Rc::new(RefCell::new(Person {
parent: None,
child: None,
name: "anakin".to_owned(),
}));
let luke = Rc::new(RefCell::new(Person {
parent: None,
child: None,
name: "luke".to_owned(),
}));
luke.borrow_mut().parent = Some(anakin.clone());
anakin.borrow_mut().child = Some(luke.clone());
println!("anakin {}", Rc::strong_count(&anakin));
println!("luke {}", Rc::strong_count(&luke));
}
代码运行时,不会打印来自 drop 实现的消息,因为该代码应该会泄漏内存。
当代码完成后,luke 和 anakin 的计数应该以 1 而不是 0 结束(此时托管堆数据将被清理)。
为什么计数最终不为 0?我原以为会发生以下顺序:
我们从堆中的两个数据位置开始,一个由 luke 和 anakin.child 指向,另一个由 anakin 和 luke.parent 指向。对象 luke 拥有 luke.parent。对象 anakin 拥有 anakin.child
luke 超出范围,这意味着它拥有的成员也被删除。所以卢克和卢克.parent 下降。两者都是 Rcs,因此两个内存位置的引用计数都下降到 1
anakin 被丢弃,导致 Rc 对象 anakin 和 anakin.child 被丢弃,这导致两个内存位置的 ref 计数降至 0。
这是应该清理堆数据的地方吗?对象被丢弃的时候,它的成员是不是也被丢弃了?
当我通过borrow_mut 删除或注释连接luke 和anakin 的行时,删除按预期发生并且消息正确打印。
【问题讨论】:
标签: memory memory-leaks rust