首页 文章

线程'<main>'在Rust中溢出了它的堆栈

提问于
浏览
4

我在尝试此代码时遇到错误,它实现了一个简单的链接列表 .

use std::rc::Rc;
use std::cell::RefCell;

struct Node {
    a : Option<Rc<RefCell<Node>>>,
    value: i32
}

impl Node {
    fn new(value: i32) -> Rc<RefCell<Node>> {
        let node = Node {
            a: None,
            value: value
        };
        Rc::new(RefCell::new(node))
    }
}

fn main() {
    let first  = Node::new(0);
    let mut t = first.clone();
    for i in 1 .. 10_000
    {
        if t.borrow().a.is_none() { 
            t.borrow_mut().a = Some(Node::new(i));
        }
        if t.borrow().a.is_some() {
            t = t.borrow().a.as_ref().unwrap().clone();
        }
    }
    println!("Done!");
}

为什么会这样?这是否意味着Rust不如定位那么安全?

UPD:如果我添加此方法,程序不会崩溃 .

impl Drop for Node {
    fn drop(&mut self) {
        let mut children = mem::replace(&mut self.a, None);

        loop {
            children = match children {
                Some(mut n) => mem::replace(&mut n.borrow_mut().a, None),
                None => break,
            }
        }
    }
}

但我不确定这是否是正确的解决方案 .

1 回答

  • 4

    这是否意味着Rust不像定位那么安全?

    Rust只能安全地抵御某些类型的故障;特别是内存损坏崩溃,这里记录:http://doc.rust-lang.org/reference.html#behavior-considered-undefined

    不幸的是,有时候人们会期望生锈对某些不是内存破坏的故障更加强大 . 具体来说,你应该阅读http://doc.rust-lang.org/reference.html#behavior-considered-undefined .

    tldr;在生锈中,许多事情都会引起恐慌 . 紧急情况将导致当前线程停止,执行关闭操作 .

    这可能表面看起来类似于内存破坏来自其他语言的崩溃,但重要的是要理解虽然它是一个应用程序失败,但它不是破坏内存的失败 .

    例如,您可以通过在不同的线程中运行操作来处理恐慌,例如异常,并在线程发生混乱时(无论出于何种原因)正常处理失败 .

    在此特定示例中,您在堆栈上占用了太多内存 .

    这个简单的例子也会失败:

    fn main() {
      let foo:&mut [i8] = &mut [1i8; 1024 * 1024];
    }
    

    (在大多数rustc;取决于特定实现的堆栈大小)

    我原本以为使用Box :: new()将分配移动到堆栈会在此示例中修复它...

    use std::rc::Rc;
    use std::cell::RefCell;
    
    #[derive(Debug)]
    struct Node {
        a : Option<Box<Rc<RefCell<Node>>>>,
        value: i32
    }
    
    impl Node {
        fn new(value: i32) -> Box<Rc<RefCell<Node>>> {
            let node = Node {
                a: None,
                value: value
            };
            Box::new(Rc::new(RefCell::new(node)))
        }
    }
    
    fn main() {
        let first  = Node::new(0);
        let mut t = first.clone();
        for i in 1 .. 10000
        {
            if t.borrow().a.is_none() {
                t.borrow_mut().a = Some(Node::new(i));
            }
            if t.borrow().a.is_some() {
                let c:Box<Rc<RefCell<Node>>>;
                { c = t.borrow().a.as_ref().unwrap().clone(); }
                t = c;
                println!("{:?}", t);
            }
        }
        println!("Done!");
    }
    

    ......但事实并非如此 . 我真的不明白为什么,但希望其他人可以看看这个,并发布一个更权威的答案,关于究竟是什么导致代码中的堆栈耗尽 .

相关问题