如何使用嵌套的ArrayLists解决StackOverflowError?

时间:2014-08-11 18:07:24

标签: java android memory arraylist stack-overflow

我在某些Android设备上运行我的项目,并且我遇到了认为与嵌套ArrayLists有关的错误。

这里是基本设置 - 我有一个由肢体组成的图形(将它们视为节点)。每个节点可以有更多的子节点,依此类推。因此,每个Node类都有一个成员ArrayList<Node> childrenNodes,其中包含任意数量的子Nodes

我无法准确找出出错的原因,但在相互连续添加~220个节点后(实质上是创建了一长串连接的节点),应用程序崩溃了。

E/AndroidRuntime(9299): FATAL EXCEPTION: GLThread 674
E/AndroidRuntime(9299): Process: __, PID: 9299
E/AndroidRuntime(9299): java.lang.StackOverflowError
E/AndroidRuntime(9299): at __.Node.getSelectedNode(Node.java:283)
E/AndroidRuntime(9299): at __.Node.getSelectedNode(Node.java:273)
E/AndroidRuntime(9299): at __.Node.getSelectedNode(Node.java:273)
E/AndroidRuntime(9299): at __.Node.getSelectedNode(Node.java:273)
...etc

函数Node::getSelectedNode迭代节点树,源自主节点,找到被点击的节点,它看起来像这样(剥离了不相关的代码):

public Node getSelectedNode(float x, float y)
{
    Node node = null;

    // First look through children (look at front-most child first, the last one).
    // ---------------------------------------------------------------------------
    for (int i = _childrenNodes.size() - 1; i >= 0; --i)
    {
        node = _childrenNodes.get(i).getSelectedNode(x, y);

        if (node != null)
            break;
    }

    // If still not found, check this node.
    // ------------------------------------
    if (node == null)
    {
        // if (this node is being clicked) {
        node = this;
    }

    return node;
}

所以我想当我调用这个函数时,堆栈会充满大量的getSelectedNode()调用,具体取决于节点的后代数量,导致StackOverflowError?

是吗?如果是这样,我真的不知道如何解决这个问题,我不应该使用ArrayList吗?

任何建议表示赞赏!


编辑:这是我发现导致StackOverflowError的另一个场景,当我克隆其中一个数字(基本上遍历每个节点并克隆它们)时。同样,这个问题似乎来自Node,有太多儿童,孙子等等......

我还99%确定没有周期,因为我已经对它进行了测试,这个问题并没有在节点数量较少的情况下发生,并且根本没有发生在桌面上(至少没​​有这么多的节点,可能更多)。

public Node(Node parentNodeRef, Node cloneFrom)
{
    // This constructor is used when cloning a Node.
    this._parentNodeRef = parentNodeRef;

    this._x = cloneFrom._x;
    this._y = cloneFrom._y;

    // ...more cloning of members here, etc...
    // this below is the problematic code, if there's too many children of children of children, etc (I got up to about 220) - I get the error

    _childrenNodes = new ArrayList<Node>(cloneFrom._childrenNodes.size());
    for (int i = 0, numChildren = cloneFrom._childrenNodes.size(); i < numChildren; ++i)
        _childrenNodes.add(new Node(this, cloneFrom._childrenNodes.get(i)));
    }
}

2 个答案:

答案 0 :(得分:1)

使用代码定义的堆栈或队列和while循环,而不是递归。

queue q = new queue()
q.push(root)
while not q.empty()
      node = q.pop()
      for each child of node
           q.push(child)
      //perform some code on current node

答案 1 :(得分:0)

  

堆栈溢出的最常见原因是过深或无限递归。像Scheme这样实现尾调用优化的语言允许在没有堆栈溢出的情况下进行特定排序尾递归的无限递归。这是有效的,因为尾递归调用不会占用额外的堆栈空间。

http://en.wikipedia.org/wiki/Stack_overflow

getSelectedNode在forloop中调用自身,它会一次又一次地调用itselg ......