【发布时间】:2014-08-12 02:54:47
【问题描述】:
我在一些 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)));
}
}
【问题讨论】:
-
您是否有可能有一个
Nodes 的循环?也就是说,节点a将b作为其子节点之一,将c作为其子节点之一,将a作为其子节点之一。 -
@rgettman - 我想过,但不,绝对不是这样,我已经运行测试以确保。
-
如果您没有循环引用,并且确实有足够的节点来填满堆栈,那么可能有更好的方法来为您的数据建模。你想做什么?
-
您的代码从不使用
x和y。 (将它们传递给自身的递归调用不算数,因为递归调用也不会使用它们。)您认为这些参数会发生什么? -
您对没有循环引用的信心如何?我很难相信你得到了一个没有循环引用的 StackOverflow。
标签: java android memory arraylist stack-overflow