【问题标题】:Out of Memory when allocating cursors分配游标时内存不足
【发布时间】:2012-09-16 15:25:48
【问题描述】:

我有一个无法解决的记忆问题。我有一个类可以完成我所有的数据库检索工作。我遇到的错误如下:

android.database.CursorWindowAllocationException: Cursor window allocation of 2048 kb failed. # Open Cursors=733 (# cursors opened by this proc=733)

执行此操作时出现内存分配错误:

mDatabaseInterface.getGraphForLevel(level);

我知道这是一个泄漏,因为我大约每 2.5 秒调用一次此方法,并且第 5 或 6 次调用很容易通过。现在这里是我的 DatabaseInterface 类中的方法:

public Graph getGraphForLevel(Level level) {

    //get the nodes
    ArrayList<Node> nodes = new ArrayList<Node>(Arrays.asList(this.getNodesWithLevel(level)));
    //get the edges
    ArrayList<Edge> edges = new ArrayList<Edge>(Arrays.asList(this.getEdgesWithNodes(nodes)));

    return new Graph(nodes, edges);
}

public Node[] getNodesWithLevel(Level level) {

    List<Node> l = new ArrayList<Node>();

    Cursor cursor = mDatabase.query("nodes", null, 
            "level = " + wrapSql(String.valueOf(level.getId())), null, null, null, null);

    while (cursor.moveToNext()) {
        l.add(parseNodeFromCursor(cursor));
    }

    cursor.close();

    return l.toArray(new Node[l.size()]);       
}

private Node parseNodeFromCursor(Cursor cursor) {

    Level l = getLevelWithId(cursor.getInt(2));

    return new Node(cursor.getInt(0), cursor.getString(1), l, 
            cursor.getInt(4), cursor.getInt(5));
}

我有很多相互调用的方法,但我知道这不是递归问题,因为这个类在另一个应用程序中工作。我的主要问题是为什么cursor.close() 不释放光标?如果我这样做:

cursor = mDatabase.query(...);
cursor.moveToNext();
Node node = new Node(cursor.getInt());
cursor.close();

这种情况下光标是否保留?

提前致谢。

【问题讨论】:

  • 只是想知道,节点和边的表有多大?
  • 现在很小,最多20行10列

标签: android sqlite memory memory-leaks android-cursor


【解决方案1】:

cursor.close() 的调用应该在finally 块中,以防在迭代时引发异常。

Cursor cursor = mDatabase.query("nodes", null, 
        "level = " + wrapSql(String.valueOf(level.getId())), null, null, null, null);
try {
    while (cursor.moveToNext()) {
        l.add(parseNodeFromCursor(cursor));
    }
} finally {
    cursor.close();
}

【讨论】:

    【解决方案2】:

    发生内存不足错误的原因之一是you are not closing your cursor

    如我所见,您正在调用cursor.close(),但您应该调用此方法还是检查是否应该在其他地方关闭它。

    编辑:

    如果您的活动是managing your Cursor,您可以考虑停止管理它并在onPause 方法中关闭所有内容,并在onResume 中再次打开所有内容并填充数据。

    【讨论】:

    • 嗯,谢谢我彻底检查了我的代码并认为我已修复它。但它在运行 10 分钟后又回来了(比 10 秒好多了!)。但是现在它崩溃了,而不是 733 个左右的游标,只打开了 4 个游标。 android.database.CursorWindowAllocationException:2048 kb 的光标窗口分配失败。 # Open Cursors=4 (# cursors open by this proc=4)
    • 好的。所以现在,如果你使用的是一个全局的 cursor 对象,首先尝试清除 cursor 的内容,然后再将其中的数据填满,这样 cursor 的内容就不会超过阈值。
    • 我没有在每个方法中都使用全局对象(而且有很多)我分配了一个游标,然后在退出方法之前关闭它。我应该使用全局对象吗?另外,我不知道你说的清除内容是什么意思
    • 是的,尝试使用全局上下文,我认为这肯定会解决问题。 (清零内容忘了,我搜了一下,不可能)
    • 实际上我不能这样做,因为我有很多嵌套查询,所以我需要在每个游标上保留一个引用,还有其他想法吗?嵌套查询的最佳做法是什么?
    猜你喜欢
    • 1970-01-01
    • 2015-08-15
    • 2011-01-11
    • 2014-02-18
    • 1970-01-01
    • 1970-01-01
    • 2014-11-16
    • 1970-01-01
    • 2020-06-25
    相关资源
    最近更新 更多