Skip to content

Latest commit

 

History

History
55 lines (43 loc) · 1.9 KB

how_rc_arc_handle_circular_refs.md

File metadata and controls

55 lines (43 loc) · 1.9 KB

By using a combination of Arc and Weak, you can break the circular reference

For example, child nodes in a tree structure could use Weak rather than Arc for their parent node

Rc/Arc 自身无法解决循环引用无法析构的问题,假设有两个节点互相引用,那么无论谁先析构双方引用计数都是从 2 减少为 1 而不会清零导致内存泄漏

所以 leetcode 的二叉树定义就很不合理,存在循环引用的字段必须定义成 Weak 类型

pub struct TreeNode {
    pub val: i32,
    pub left: Option<Rc<RefCell<TreeNode>>>,
    pub right: Option<Rc<RefCell<TreeNode>>>,
}

首先二叉树左右叶子节点肯定不会有多个引用,用 Option Box 足够了,假设还要加一个指向父节点的引用,就用 Weak

#[derive(serde::Serialize)]
struct Node {
    val: i32,
    left: Option<Box<Node>>,
    right: Option<Box<Node>>,
    parent: Option<std::rc::Weak<Node>>,
}
fn main() {
    let root_node = std::rc::Rc::new_cyclic(|self_| Node {
        val: 0,
        left: Some(Box::new(Node {
            val: 1,
            left: None,
            right: None,
            parent: Some(self_.clone()),
        })),
        right: None,
        parent: None,
    });
    // serde rc feature stack overflow on cyclic /~https://github.com/serde-rs/serde/issues/2543
    let json = serde_json::to_string(&root_node).unwrap();
    println!("{json}");
}

但 Weak 没有 new 方法,创建的时候需要从 Arc 中 downgrade 一个出来

所以 Arc 内部有强弱引用两个 AtomicUsize downgrade 也是克隆但只有弱引用计数加一


无 GC 不是吞吐量友好而是延迟友好,所以 Go 有些业务比 Rust 吞吐量好正常,有人评测 Go 写的 js 编译器比 swc 性能好也正常

有 GC 也需要引入弱引用解决循环引用问题例如 Python 标准的 weakref