SQLite
 sql >> Base de Dados >  >> RDS >> SQLite

Problema de memória SQLite com abordagem singleton


Se você estiver recebendo uma mensagem indicando que há muitos arquivos abertos, uma causa pode ser que há muitos cursores ainda abertos.

No entanto, a mensagem retornada pode não ser sempre a mesma e provavelmente é específica para a tarefa/chamada que está sendo chamada.

Nesse caso, a mensagem era (unable to open database file (code 2062)) , ainda em outro caso (de um SELECT a mensagem foi unable to open database file (code 14) ). SQLite incapaz de abrir o arquivo de banco de dados (código 14) na consulta “SELECT” frequente.

O link acima também aponta para um post que fiz o que mostra claramente que a criação de um cursor resulta em um arquivo (ou arquivos) sendo aberto.

O exemplo estava percorrendo cerca de 500 linhas e para cada linha estava criando/recriando 3 cursores para cada linha (portanto, potencialmente mais de 1500 cursores, embora usando apenas 4 objetos de cursor).

Inicialmente, estava apenas fechando os 3 cursores no final (última linha do pai de todos) resultando no unable to open database File (code 14) . Fechar os 3 cursores para cada iteração resolveu o problema.

O código que falhou foi:-
        SQLiteDatabase db = getWritableDatabase();
        Cursor shoplistcursor = getAllRowsFromTable(SHOPLIST_TABLE_NAME);
        Cursor productcsr;
        Cursor aislecsr;
        Cursor prdusecsr;
        while(shoplistcursor.moveToNext()) {
            productcsr = getProductFromProductId(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_PRODUCTREF)));
            aislecsr = getAisleFromAisleId(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_AISLEREF)));
            prdusecsr = getProductUsage(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_AISLEREF)),
                    shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_PRODUCTREF)));
            if (productcsr.getCount() < 1 | aislecsr.getCount() < 1 | prdusecsr.getCount() < 1) {
                deleteShopListEntry(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_ID)));
            } 
            if(shoplistcursor.isLast()) {
                prdusecsr.close();
                aislecsr.close();
                productcsr.close();
            }
        }
        shoplistcursor.close();
        db.close();
}

Enquanto o código fixo foi:-
        SQLiteDatabase db = getWritableDatabase();
        Cursor shoplistcursor = getAllRowsFromTable(SHOPLIST_TABLE_NAME);
        Cursor productcsr;
        Cursor aislecsr;
        Cursor prdusecsr;
        while(shoplistcursor.moveToNext()) {
            productcsr = getProductFromProductId(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_PRODUCTREF)));
            aislecsr = getAisleFromAisleId(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_AISLEREF)));
            prdusecsr = getProductUsage(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_AISLEREF)),
                    shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_PRODUCTREF)));
            if (productcsr.getCount() < 1 | aislecsr.getCount() < 1 | prdusecsr.getCount() < 1) {
                productcsr.close();
                aislecsr.close();
                prdusecsr.close();
                deleteShopListEntry(shoplistcursor.getLong(shoplistcursor.getColumnIndex(SHOPLIST_COLUMN_ID)));
            } else {
                productcsr.close();
                aislecsr.close();
                prdusecsr.close();
            }
        }
        shoplistcursor.close();
        db.close();
    }

Eu costumo seguir agora a seguinte regra/prática:-

  • Se apenas obter o resultado, por exemplo. obtendo o número de linhas, feche o Cursor no método.

  • Se estiver usando o Cursor para uma exibição, por exemplo, um ListView e, em seguida, feche o cursor no onDestroy da atividade método.

  • Se estiver usando o Cursor para o que chamarei de processamento mais complexo, por exemplo. excluir linhas com referências subjacentes e fechar os cursores assim que terminar, dentro do(s) loop(s) de processamento.