简体   繁体   English

“线 &#39;<main> &#39; 已溢出其堆栈” 构造大树时

[英]“thread '<main>' has overflowed its stack” when constructing a large tree

I implemented a tree struct:我实现了一个树结构:

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

struct A {
    children: Option<VecDeque<Rc<RefCell<A>>>>
}

// I got thread '<main>' has overflowed its stack
fn main(){
    let mut tree_stack: VecDeque<Rc<RefCell<A>>> = VecDeque::new();

    // when num is 1000, everything works
    for i in 0..100000 {
        tree_stack.push_back(Rc::new(RefCell::new(A {children: None})));
    }

    println!("{:?}", "reach here means we are not out of mem");
    loop {
        if tree_stack.len() == 1 {break;}

        let mut new_tree_node = Rc::new(RefCell::new(A {children: None}));
        let mut tree_node_children: VecDeque<Rc<RefCell<A>>> = VecDeque::new();

        // combine last two nodes to one new node
        match tree_stack.pop_back() {
            Some(x) => {
                tree_node_children.push_front(x);
            },
            None => {}
        } 
        match tree_stack.pop_back() {
            Some(x) => {
                tree_node_children.push_front(x);
            },
            None => {}
        } 

        new_tree_node.borrow_mut().children = Some(tree_node_children);
        tree_stack.push_back(new_tree_node);
    }
}

Playpen link围栏链接

But it crashes with但它崩溃了

thread '<main>' has overflowed its stack

How do I fix that?我该如何解决?

The problem that you are experiencing is because you have a giant linked-list of nodes.您遇到的问题是因为您有一个巨大的节点链表。 When that list is dropped, the first element tries to free all the members of the struct first.当该列表被删除时,第一个元素首先尝试释放结构的所有成员。 That means that the second element does the same, and so on, until the end of the list.这意味着第二个元素做同样的事情,依此类推,直到列表的末尾。 This means that you will have a call stack that is proportional to the number of elements in your list!这意味着您将拥有一个与列表中元素数量成正比的调用堆栈!

Here's a small reproduction:这是一个小复制:

struct A {
    children: Option<Box<A>>
}

fn main() {
    let mut list = A { children: None };

    for _ in 0..1_000_000 {
        list = A { children: Some(Box::new(list)) };
    }
}

And here's how you would fix it:以下是您的修复方法:

impl Drop for A {
    fn drop(&mut self) {
        if let Some(mut child) = self.children.take() {
            while let Some(next) = child.children.take() {
                child = next;
            }
        }
    }
}

This code overrides the default recursive drop implementation with an iterative one.此代码使用迭代覆盖了默认的递归放置实现。 It rips the children out of the node, replacing it with a terminal item ( None ).它将children节点从节点中剥离出来,用一个终端项( None )替换它。 It then allows the node to drop normally, but there will be no recursive calls.然后它允许节点正常丢弃,但不会有递归调用。

The code is complicated a bit because we can't drop ourselves, so we need to do a little two-step dance to ignore the first item and then eat up all the children.代码有点复杂,因为我们放不下自己,所以我们需要做一点两步舞,忽略第一项,然后把所有孩子都吃掉。

See also:也可以看看:

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

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