18

I have a memory problem that I can't figure out. I have one class that does all my database retrieving work. The error I have is the following:

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

The memory allocation error occurs when I do this:

mDatabaseInterface.getGraphForLevel(level);

I know it's a leak because I call this method every 2.5 seconds roughly, and the 5 or 6 first calls go through easily. Now here are the methods in my DatabaseInterface class:

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

I have a lot of methods that call each other but I know it's not a recursion problem because this class works in another app. My main question is why doesn't cursor.close() liberate the cursor? If I do something like:

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

Is the cursor retained in that case?

Thanks in advance.

General Grievance
  • 4,555
  • 31
  • 31
  • 45
chopchop
  • 1,905
  • 2
  • 22
  • 37

2 Answers2

27

The call to cursor.close() should be in a finally block in case an exception is thrown while you're iterating over it.

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();
}
Graham Borland
  • 60,055
  • 21
  • 138
  • 179
10

One of the reasons for occurring Out of Memory error is you are not closing your cursor.

As I can see, you are calling cursor.close(), but is it the right place where you should call this method or check if you should close it on some other place.

EDIT:

If your activity is managing your Cursor, you may consider stop managing it and closing everything in the onPause method, and in onResume open everything up and fillData once again.

Shrikant Ballal
  • 7,067
  • 7
  • 41
  • 61
  • 1
    mmm thanks I thoroughly checked my code and thought I fixed it. But it came back after 10 minutes of running (a lot better than 10 seconds!). But now instead of 733 or so cursors it crashes with only 4 cursors opened. android.database.CursorWindowAllocationException: Cursor window allocation of 2048 kb failed. # Open Cursors=4 (# cursors opened by this proc=4) – chopchop Sep 25 '12 at 07:01
  • 1
    Okay. So now, if you are using a global object of cursor, first try clearing the contents of cursor and then fill up the data in it again, so that, the contents of cursor will not exceed the threshold. – Shrikant Ballal Sep 25 '12 at 07:14
  • I'm not using a global object in every method (and there's a lot) I allocate a cursor then close it before exiting the method. Should I use a global object? also, I'm not sure what you mean by clearing the content – chopchop Sep 25 '12 at 07:55
  • Yes, try to use a global context, I think that will definitely solve the problem. (Forget about the clearing contents, I searched about it, its not possible) – Shrikant Ballal Sep 25 '12 at 08:11
  • Actually I can't do that because I have a lot of nested queries so I need to keep a ref on each cursor, any other ideas? What's best practice for nested queries? – chopchop Sep 25 '12 at 08:23
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/17152/discussion-between-chopchop-and-shrikant) – chopchop Sep 25 '12 at 22:48