SQLite
 sql >> Base de données >  >> RDS >> SQLite

Problème de mémoire SQLite avec l'approche singleton

Si vous recevez un message indiquant qu'un trop grand nombre de fichiers sont ouverts, il se peut qu'il y ait trop de curseurs encore ouverts.

Cependant, le message renvoyé peut ne pas toujours être le même et est probablement spécifique à la tâche/appel appelé.

Dans ce cas, le message était (unable to open database file (code 2062)) , mais dans un autre cas (à partir d'un SELECT, le message était unable to open database file (code 14) ). SQLite incapable d'ouvrir le fichier de base de données (code 14) sur une requête "SELECT" fréquente.

Le lien ci-dessus pointe également vers un article que j'ai rédigé, ce qui montre clairement que la création d'un curseur entraîne l'ouverture d'un ou de plusieurs fichiers.

L'exemple parcourait environ 500 lignes et pour chaque ligne, il créait/recréait 3 curseurs pour chaque ligne (donc potentiellement plus de 1500 curseurs même en n'utilisant que 4 objets curseur).

Initialement, il ne fermait que les 3 curseurs à la fin (dernière ligne du parent de tous), ce qui entraînait le unable to open database file (code 14) . La fermeture des 3 curseurs pour chaque itération a résolu le problème.

Le code qui a échoué était :-

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

Alors que le code fixe était :-

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

J'ai tendance à suivre la règle/pratique suivante :-

  • Si vous obtenez simplement le résultat, par ex. obtenir le nombre de lignes, fermez le curseur dans la méthode.

  • Si vous utilisez le curseur pour un affichage, par ex. un ListView, puis fermez le curseur dans le onDestroy de l'activité méthode.

  • Si vous utilisez le curseur pour ce que j'appellerai un traitement plus complexe, par ex. supprimer les lignes avec des références sous-jacentes puis fermer les curseurs dès qu'ils en ont terminé, dans la ou les boucles de traitement.