简体   繁体   English

线 &#39;<main> &#39; 在 Rust 中溢出了它的堆栈

[英]thread '<main>' has overflowed its stack in Rust

I got an error trying this code, which realizes a simple linked list.尝试此代码时出现错误,该代码实现了一个简单的链表。

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!");
}

Why does it happen?为什么会发生? Does this mean that Rust is not as safe as positioned?这是否意味着 Rust 不如定位安全?

UPD: If I add this method, the program does not crash. 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,
            }
        }
    }
}

But I am not sure that this is the right solution.但我不确定这是正确的解决方案。

Does this mean that Rust is not as safe as positioned?这是否意味着 Rust 不如定位安全?

Rust is only safe against certain kinds of failures; Rust 只对某些类型的故障是安全的; specifically memory corrupting crashes, which are documented here: http://doc.rust-lang.org/reference.html#behavior-considered-undefined特别是内存破坏崩溃,这里记录: http : //doc.rust-lang.org/reference.html#behavior-thinked-undefined

Unfortunately there is a tendency to sometimes expect rust to be more robust against certain sorts of failures that are not memory corrupting.不幸的是,有时人们倾向于认为 Rust 对某些非内存损坏的故障更加健壮。 Specifically, you should read http://doc.rust-lang.org/reference.html#behavior-considered-undefined .具体来说,您应该阅读http://doc.rust-lang.org/reference.html#behavior-thinked-undefined

tldr; tldr; In rust, many things can cause a panic.在 Rust 中,很多事情都会引起恐慌。 A panic will cause the current thread to halt, performing shutdown operations.恐慌会导致当前线程停止,执行关闭操作。

This may superficially appear similar to a memory corrupting crash from other languages, but it is important to understand although it is an application failure , it is not a memory corrupting failure.这可能表面上看起来类似于其他语言的内存损坏崩溃,但重要的是要理解虽然它是应用程序故障,但它不是内存损坏故障。

For example, you can treat panic's like exceptions by running actions in a different thread and gracefully handling failure when the thread panics (for whatever reason).例如,您可以通过在不同的线程中运行操作并在线程恐慌(无论出于何种原因)时优雅地处理失败来将恐慌视为异常。

In this specific example, you're using up too much memory on the stack.在此特定示例中,您在堆栈上使用了过多内存。

This simple example will also fail:这个简单的例子也会失败:

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

(On most rustc; depending on the stack size on that particularly implementation) (在大多数 rustc 上;取决于特定实现的堆栈大小)

I would have thought that moving your allocations to the stack using Box::new() would fix it in this example...我原以为在这个例子中使用 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!");
}

...but it doesn't. ......但它没有。 I don't really understand why, but hopefully someone else can look at this and post a more authoritative answer about what exactly is causing stack exhaustion in your code.我真的不明白为什么,但希望其他人可以看看这个并发布一个更权威的答案,说明究竟是什么导致了代码中的堆栈耗尽。

For those who come here and are specifically interested in the case where the large struct is a contiguous chunk of memory (instead of a tree of boxes), I found this GitHub issue with further discussion, as well as a solution that worked for me: https://github.com/rust-lang/rust/issues/53827对于那些来到这里并对大型结构是连续内存块(而不是一棵盒子树)的情况特别感兴趣的人,我发现了这个 GitHub 问题并进行了进一步的讨论,以及一个对我有用的解决方案: https://github.com/rust-lang/rust/issues/53827

Vec's method into_boxed_slice() returns a Box<[T]> , and does not overflow the stack for me. Vec 的方法into_boxed_slice()返回一个Box<[T]> ,并且不会为我溢出堆栈。

vec![-1; 3000000].into_boxed_slice()

A note of difference with the vec!与 vec 的不同之处! macro and array expressions from the docs:文档中的宏和数组表达式:

This will use clone to duplicate an expression, so one should be careful using this with types having a nonstandard Clone implementation.这将使用 clone 来复制表达式,因此对于具有非标准 Clone 实现的类型使用它时应该小心。

There is also the with_capacity() method on Vec, which is shown in the into_boxed_slice() examples. Vec 上还有with_capacity()方法,如into_boxed_slice()示例中所示。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM