使用 RefCell 和 Rc 处理循环图中的内存泄漏

Posted

技术标签:

【中文标题】使用 RefCell 和 Rc 处理循环图中的内存泄漏【英文标题】:Handling memory leak in cyclic graphs using RefCell and Rc 【发布时间】:2018-05-29 02:04:09 【问题描述】:

我按照https://ricardomartins.cc/2016/06/08/interior-mutability 中提到的方法使用RcRefCell 在Rust 中创建图形。

type NodeRef<i32> = Rc<RefCell<_Node<i32>>>;

#[derive(Clone)]
// The private representation of a node.
struct _Node<i32> 
    inner_value: i32,
    adjacent: Vec<NodeRef<i32>>,

#[derive(Clone)]
// The public representation of a node, with some syntactic sugar.
struct Node<i32>(NodeRef<i32>);

impl<i32> Node<i32> 
    // Creates a new node with no edges.
    fn new(inner: i32) -> Node<i32> 
        let node = _Node  inner_value: inner, adjacent: vec![] ;
        Node(Rc::new(RefCell::new(node)))
    

    // Adds a directed edge from this node to other node.
    fn add_adjacent(&self, other: &Node<i32>) 
        (self.0.borrow_mut()).adjacent.push(other.0.clone());
    

#[derive(Clone)]
struct Graph<i32> 
    nodes: Vec<Node<i32>>,


impl<i32> Graph<i32> 
    fn with_nodes(nodes: Vec<Node<i32>>) -> Self 
        Graph  nodes: nodes 
    


我认为这种方法在循环图的情况下会导致内存泄漏。我该如何解决?

【问题讨论】:

【参考方案1】:

您无需阅读博文即可找到答案,只需read the documentation:

Rc 指针之间的循环永远不会被释放。出于这个原因,Weak 用于中断循环。例如,一棵树可能具有从父节点到子节点的强 Rc 指针,以及从子节点返回父节点的 Weak 指针。

另见:

Is there a way to build a structure with cyclic links without runtime overhead? Implement graph-like datastructure in Rust Recursive Data Structures in Rust

【讨论】:

嗯,这是否意味着对于您插入的每条边,您将查看整个图形以检查这条边是否会创建一个循环?我确实读过,如果您希望孩子指向父母,您可以在树中使用弱指针。但我不知道在图表的情况下如何翻译?图中的弱指针是什么意思? @user9097180 您即将开始探索为什么在垃圾回收和非 GC 语言中,究竟图对于内存管理来说是非常困难的概念。如果您(人类)无法确定一个过程来确定图中哪些链接是强链接,哪些链接是弱链接,那么编译器/运行时将如何?也许如果您的节点有一些排序,您可以为“较大”节点做强引用,为“较小”节点做弱引用(我不知道这是否可行)。 @user9097180:此时,您可能需要查找petgraph crate。

以上是关于使用 RefCell 和 Rc 处理循环图中的内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

Rc<RefCell<T>> 和 RefCell<Rc<T>> 有啥区别?

如何正确访问 RefCell 中的值

Rayon 如何防止线程之间使用 RefCell<T>、Cell<T> 和 Rc<T>?

Cell 或 RefCell 是最佳选择的情况

是否有替代方法或方法让 Rc<RefCell<X>> 限制 X 的可变性?

如何将 Rc<RefCell<_>> 中的具体对象转换为动态特征对象? [复制]