sql >> Base de Datos >  >> RDS >> SQLite

Problema de memoria SQLite con enfoque singleton

Si recibe un mensaje que indica que hay demasiados archivos abiertos, es posible que la causa sea que hay demasiados cursores abiertos.

Sin embargo, es posible que el mensaje devuelto no siempre sea el mismo y probablemente sea específico de la tarea/llamada a la que se llama.

En este caso, el mensaje era (unable to open database file (code 2062)) , sin embargo, en otro caso (desde un SELECT, el mensaje fue unable to open database file (code 14) ). SQLite no puede abrir el archivo de la base de datos (código 14) en la consulta frecuente "SELECCIONAR".

El enlace anterior también apunta a una publicación que hice que muestra claramente que la creación de un Cursor da como resultado la apertura de un archivo (o archivos).

El ejemplo estaba recorriendo alrededor de 500 filas y para cada fila estaba creando/recreando 3 cursores para cada fila (por lo tanto, potencialmente más de 1500 cursores aunque solo se usaran 4 objetos de cursor).

Inicialmente, solo cerraba los 3 cursores al final (última fila del padre de todos), lo que resultaba en unable to open database file (code 14) . Cerrar los 3 cursores para cada iteración resolvió el problema.

El código que falló fue :-

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

Mientras que el código fijo era:-

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

Ahora tiendo a seguir la siguiente regla/práctica:-

  • Si solo obtiene el resultado, p. obteniendo el número de filas, cierre el Cursor en el método.

  • Si usa el cursor para una pantalla, p. un ListView, luego cierre el cursor en onDestroy de la actividad método.

  • Si usa el Cursor para lo que llamaré un procesamiento más complejo, p. eliminando filas con referencias subyacentes y luego cierre los cursores tan pronto como terminen, dentro de los bucles de procesamiento.