«Ошибка 21 (недостаточно памяти)» при выполнении некоторых операций SQLite - PullRequest
1 голос
/ 16 августа 2011

Мое приложение синхронизирует свою локальную базу данных SQLite с внешней базой данных, которая существует на серверах Amazon. Иногда синхронизация завершается неудачно и выдает такой вывод logcat:

08-15 19:58:38.149: ERROR/Database(343): Failure 21 (out of memory) on 0x0 when preparing 'drop table if exists keymap2'.
08-15 19:58:38.149: ERROR/KeymapDbHelper(343): Error occurred while syncing DB
08-15 19:58:38.149: ERROR/KeymapDbHelper(343): android.database.sqlite.SQLiteException: unknown error: drop table if exists keymap2
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at android.database.sqlite.SQLiteDatabase.native_execSQL(Native Method)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at android.database.sqlite.SQLiteDatabase.execSQL(SQLiteDatabase.java:1610)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at lee.medical.icu.dataentry.db.KeymapDbHelper.syncToTempTable(KeymapDbHelper.java:114)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at lee.medical.icu.dataentry.db.KeymapDbHelper.syncDb(KeymapDbHelper.java:84)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at lee.medical.icu.dataentry.MainMenuActivity$DbSyncTask.doInBackground(MainMenuActivity.java:221)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at lee.medical.icu.dataentry.MainMenuActivity$DbSyncTask.doInBackground(MainMenuActivity.java:1)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at android.os.AsyncTask$2.call(AsyncTask.java:185)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at java.util.concurrent.FutureTask.run(FutureTask.java:137)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1068)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
08-15 19:58:38.149: ERROR/KeymapDbHelper(343):     at java.lang.Thread.run(Thread.java:1096)

Когда это происходит, мое приложение уведомляет меня о сбое синхронизации, поэтому я прошу его снова попытаться выполнить синхронизацию, что работает примерно в 50-75% случаев.

Вот код, который выполняет синхронизацию:

@SuppressWarnings("unchecked")
private void syncToTempTable(SQLiteDatabase db, String table)
        throws DatabaseMismatchException {
    String awsSql = "select * from " + keymapDb;
    SelectRequest select = new SelectRequest(awsSql);
    SelectResult result;

    Log.d(TAG, "Making request: " + awsSql);
    result = simpleDB.select(select); // Could throw AmazonClientException

    List<Item> items = result.getItems();

    db.execSQL("drop table if exists " + table);
    String tempSql = "create table " + table + " (" +
            C_KEY + " text primary key, " +
            C_NAME + " text)";
    db.execSQL(tempSql);
    Log.d(TAG, "SQL executed: " + tempSql);

    ContentValues cv = new ContentValues();
    for (Item i : items) {
        cv.clear();
        String key = i.getName();
        cv.put(C_KEY, key);

        List<Attribute> attributes = i.getAttributes();
        assert attributes.size() <= 1;
        for (Attribute a : attributes) {
            String name = a.getName();
            String value = a.getValue();

            if ((key.equals(R_INFO) && !name.equals(C_REVISION)) || 
                    (!key.equals(R_INFO) && !name.equals(C_NAME)))
                throw new DatabaseMismatchException("DB not synced because " +
                        "column " + name + " was unexpected");

            cv.put(C_NAME, value);
        }

        db.insert(table, null, cv);
    }
}

Строка 114 - db.execSQL("drop table if exists " + table);

Цель этой строки - удалить временную таблицу, если по какой-то причине приложение было аварийно сброшено и предотвратило удаление таблицы, как это обычно происходит. Я заметил, что если эту таблицу оставить в покое, приложение будет зависать при попытке создать новую таблицу с тем же именем.

Почему моему приложению не хватает памяти и что я могу сделать, чтобы это исправить?

Редактировать: Хорошо, это на самом деле происходит каждый раз, когда приложение синхронизируется с внешней базой данных.

1 Ответ

5 голосов
/ 19 августа 2011

Оказывается, эта ошибка была результатом ошибки программирования до того, как мое приложение вызвало этот метод.Перед тем как позвонить на syncToTempTable(), я открыл базу данных:

SQLiteDatabase db = dbHelper.getWritableDatabase();

Сразу после этого я захотел проверить номер ревизии локальной базы данных.Метод, который я использовал для этого, также открывал базу данных (поэтому в основном я открыл свою базу данных дважды), а затем закрыл ее (что, вероятно, закрыло все открытые потоки для базы данных).Из-за этого я не осознавал, что предоставляю syncToTempTable() закрытую базу данных.

Проблема решена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...