Не хватает памяти при выделении курсоров
У меня есть проблема с памятью, которую я не могу понять. У меня есть один класс, который выполняет всю мою работу по извлечению базы данных. Ошибка у меня следующая:
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();
Сохраняется ли курсор в этом случае?
Заранее благодарю.
2 ответа:
Вызов
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(); }
Одной из причин возникновения ошибки выхода из памяти является
you are not closing your cursor
.Как я вижу, вы вызываете
cursor.close()
, но это правильное место, где вы должны вызвать этот метод или проверить, если вы должны закрыть его на каком-то другом месте.Редактировать:
Если ваша активность
managing your Cursor
, Вы можете подумать о том, чтобы перестать управлять ею и закрыть все в методеonPause
, а вonResume
открыть все и заполнить еще раз.