在 Rust 中,Weak<T> 如何知道内部值何时被删除?

Cal*_*yne 7 memory-management weak-references smart-pointers reference-counting rust

std::rc::Weak<T>有以下定义:

pub struct Weak<T: ?Sized> {
    ptr: NonNull<RcBox<T>>,
}
Run Code Online (Sandbox Code Playgroud)

根据我的理解,当没有剩下的时候Rc<T>RcBox<T>将被释放,Weak<T>.ptr现在指向一个可能包含任何东西的地方。那么当在upgrade()a 上调​​用时Weak<T>,它如何知道指针现在无效?

Weak<T>::upgrade有以下实现:

    pub fn upgrade(&self) -> Option<Rc<T>> {
        let inner = self.inner()?;

        if inner.strong() == 0 {
            None
        } else {
            unsafe {
                inner.inc_strong();
                Some(Rc::from_inner(self.ptr))
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

这是否意味着当野外RcBox<T>没有剩余的时候就没有真正获得自由?Rc<T>如果是的话,那不是会泄漏内存吗?

cdh*_*wie 11

RcBox直到没有强指针弱指针剩余时才会被销毁。

然而,当强计数达到零时,所包含的内容T就会被丢弃。这有效地破坏了所包含的内容T,但并没有释放其本身的内存T。这就是如何Weak知道内部值是否被删除 - 如果您尝试在强计数为零时将 a 升级Weak到 an Rc,则操作会失败并返回None

一旦弱计数也达到零,它RcBox本身就会被释放。所以不,不存在内存泄漏。

请注意,许多类型(例如StringVec)管理单独的堆分配。例如,如果您有一个Rc<Vec<_>>,当强计数达到零但弱计数没有达到零时,内部的删除代码将Vec运行并删除其拥有的所有元素,并释放用于存储它们的堆分配。自身用于Vec保存堆指针、长度和容量的内存不会被释放,因为它由RcBox. 仅当强计数和弱计数都达到零时,该分配才会被释放。

  • 这就是“Weak”使循环成为可能的方式,因为“Rc”的删除将导致“Weak”被删除。 (2认同)