网站首页 全球最实用的IT互联网站!

人工智能P2P分享Wind搜索发布信息网站地图标签大全

当前位置:诺佳网 > 软件工程 > 后端开发 > Rust >

rust学习十五.5、引用循环和内存泄露

时间:2025-01-07 20:35

人气:

作者:admin

标签:

导读:这个章节主要是为了引出弱引用这个奇怪的概念。 说实在,这个没有什么太好写的,因为内容比较晦涩难懂! 在其它语言中,也常常存在所谓循环引用问题,和大部分问题一样,在其它...

这个章节主要是为了引出弱引用这个奇怪的概念。

说实在,这个没有什么太好写的,因为内容比较晦涩难懂!

 

在其它语言中,也常常存在所谓循环引用问题,和大部分问题一样,在其它语言中这些基本上都不是问题。但是在rust中,这是一个致命的问题。

 

例如有a,b两个点,a指向b,b指向a。

如果根据截止当前的知识(所有权、一个数据也可以有多个所有者),那么rust可能无法释放a所实际指向的数据,或者是因为循环递归导致堆栈溢出。

或者其实我们也没有必要知道为什么,只要知道结论即可,毕竟如果我们不看编译器是怎么写的。所以,有的时候就是看到了概念,看到了例子也是难以理解。

 

这些都需要借助于一些概念和例子来理解。

堆栈溢出示例(来自原书):

use crate::List::{Cons, Nil};
use std::cell::RefCell;
use std::rc::Rc;

#[derive(Debug)]
enum List {
    Cons(i32, RefCell<Rc<List>>),
    Nil,
}

impl List {
    fn tail(&self) -> Option<&RefCell<Rc<List>>> {
        match self {
            Cons(_, item) => Some(item),
            Nil => None,
        }
    }
}

fn main() {
    let a = Rc::new(Cons(5, RefCell::new(Rc::new(Nil))));

    println!("a initial rc count = {}", Rc::strong_count(&a));
    println!("a next item = {:?}", a.tail());

    let b = Rc::new(Cons(10, RefCell::new(Rc::clone(&a))));

    println!("a rc count after b creation = {}", Rc::strong_count(&a));
    println!("b initial rc count = {}", Rc::strong_count(&b));
    println!("b next item = {:?}", b.tail());

    if let Some(link) = a.tail() {
        *link.borrow_mut() = Rc::clone(&b);
    }

    println!("b rc count after changing a = {}", Rc::strong_count(&b));
    println!("a rc count after changing a = {}", Rc::strong_count(&a));

    // Uncomment the next line to see that we have a cycle;
    // it will overflow the stack
    // println!("a next item = {:?}", a.tail());
}

 

rust在做匹配的时候,会不断找尾巴,结果循着尾巴一直找.....

 

rust推出一个新的概念:弱引用(weak reference)

所谓弱引用,即指向某个数据,但是这种引用不会产生所有权方面的问题,就如同大部分其它语言那样的美好。

 

一、重要概念

Rc::downgrade Rc::downgrade 会将 weak_count 加 1,同时返回Weak<T>指针 这个函数用于构建弱引用   Weak::upgrade() Weak<T> 实例的 upgrade 方法,这会返回 Option<Rc<T>>  

二、例子

书上例子很完善,稍微修改了下:

use std::cell::RefCell;
use std::rc::{ Rc, Weak };

#[derive(Debug)]
struct Node {
    value: i32,
    parent: RefCell<Weak<Node>>,
    children: RefCell<Vec<Rc<Node>>>,
}

fn main() {
    look_weak_ref();
}

fn look_weak_ref() {
    let leaf = Rc::new(Node {
        value: 3,
        parent: RefCell::new(Weak::new()),
        children: RefCell::new(vec![]),
    });

    println!("leaf strong = {}, weak = {}", Rc::strong_count(&leaf), Rc::weak_count(&leaf));
    {
        println!("------------------------------------------------------------------------------");

        let branch = Rc::new(Node {
            value: 5,
            parent: RefCell::new(Weak::new()),
            children: RefCell::new(vec![Rc::clone(&leaf)]),
        });
        *leaf.parent.borrow_mut() = Rc::downgrade(&branch);
        println!("branch strong = {}, weak = {}",Rc::strong_count(&branch),Rc::weak_count(&branch));
        println!("leaf strong = {}, weak = {}", Rc::strong_count(&leaf), Rc::weak_count(&leaf));
        println!("------------------------------------------------------------------------------");
    }

    println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
    println!("leaf strong = {}, weak = {}", Rc::strong_count(&leaf), Rc::weak_count(&leaf));
}

 

三、小结

如果我们成心构建导致堆栈溢出的死循环,还是可以的,书上也有这个例子。

但rust提供了可以避免这个的方法,毕竟这种需求还是不鲜见的!

 

本文来自博客园,作者:正在战斗中,转载请注明原文链接:https://www.cnblogs.com/lzfhope/p/18655762

温馨提示:以上内容整理于网络,仅供参考,如果对您有帮助,留下您的阅读感言吧!
相关阅读
本类排行
相关标签
本类推荐

CPU | 内存 | 硬盘 | 显卡 | 显示器 | 主板 | 电源 | 键鼠 | 网站地图

Copyright © 2025-2035 诺佳网 版权所有 备案号:赣ICP备2025066733号
本站资料均来源互联网收集整理,作品版权归作者所有,如果侵犯了您的版权,请跟我们联系。

关注微信