分配游标时内存不足

18

我有一个记忆问题,无法解决。我有一个类来处理所有的数据库检索工作。我遇到的错误是:

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();

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

提前谢谢。


仅仅为了了解一下,节点和边的表有多大? - Matthieu
它们现在非常小,最多只有20行和10列。 - chopchop
2个回答

27

如果在迭代过程中抛出异常,那么调用 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();
}

10

导致内存不足错误发生的原因之一是您没有关闭游标

我看到您调用了cursor.close(),但是您是否在正确的位置调用此方法或检查是否应在其他位置关闭它。

编辑:

如果您的活动正在管理游标,则可以考虑停止管理并在onPause方法中关闭所有内容,在onResume中再次打开所有内容并重新填充数据。


1
谢谢,我仔细检查了我的代码并认为我已经修复了它。但是在运行了10分钟后它又出现了(比10秒好多了!)。但现在,它崩溃时只打开了4个光标,而不是733个左右。android.database.CursorWindowAllocationException:分配2048 kb的光标窗口失败。#打开的光标= 4(此进程打开的光标数= 4) - chopchop
1
好的。现在,如果您正在使用全局游标对象,请首先尝试清除游标的内容,然后再次填充数据,以便游标的内容不会超过阈值。 - Shrikant Ballal
我并没有在每个方法中使用全局对象(而且有很多方法),我会分配一个游标,然后在退出方法之前关闭它。我应该使用全局对象吗?另外,我不确定您所说的清除内容是什么意思。 - chopchop
是的,请尝试使用全局上下文,我认为这肯定会解决问题。(忘记清除内容,我搜索了一下,这是不可能的) - Shrikant Ballal
实际上我不能这样做,因为我有很多嵌套查询,所以我需要在每个游标上保持引用,还有其他的想法吗?嵌套查询的最佳实践是什么? - chopchop
让我们在聊天中继续这个讨论。点击此处进入聊天室 - chopchop

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接