分配2048 kb的游标窗口失败。#打开的游标数=1(此进程打开的游标数=1)

7
我正在制作一个使用数据库的Kiosk应用程序。该应用程序在前台一直运行,有许多线程使用共享的DataBaseHelper实例。该应用程序运行良好,但大多数情况下在5或6个小时后,我会遇到以下异常,然后应用程序崩溃:
``` E/DataBaseHelper: Cursor window allocation of 2048 kb failed. # Open Cursors=1 (# cursors opened by this proc=1) E/CursorWindow: Could not allocate CursorWindow '/data/user/0/com.kios.frm/databases/YadProjectDB.db' of size 2097152 due to error -24. E/SQLiteLog: (14) cannot open file at line 30192 of [00bb9c9ce4] E/SQLiteLog: (14) statement aborts at 16: [SELECT number FROM sms LIMIT 5] unable to open database file E/SQLiteQuery: exception: unable to open database file (code 14); query: SELECT number FROM sms LIMIT 5 E/SQLiteLog: (14) os_unix.c:30192: (24) open(/data/user/0/com.kiosk.frm/databases/YadProjectDB.db-journal)- ```
我已经正确关闭了游标,但仍然会遇到这些异常。这些异常是什么?这些异常的原因是什么? MainActivity
private DataBaseHelper db = null; // Global     

MainActivity onCreate 方法:

db = new DataBaseHelper(this);

new Thread(new Runnable() {
@Override
public void run() {
    while (threadRunningFlag) {

    Cursor result = null;
    try {

        result = db.getData("SELECT " + DataBaseHelper.SMS_COLUMN_PHONE_NUMBER  + " FROM " + DataBaseHelper.SMS_TABLE_NAME + " LIMIT 5");
        if (result != null && result.getCount() > 0) {
            while (!result.isAfterLast()) {
                String phoneNumber = result.getString(result.getColumnIndex(DataBaseHelper.SMS_COLUMN_PHONE_NUMBER));
                // ...
                result.moveToNext();
            }
        }
    }catch (Exception e) {
        Log.e(TAG, "err->" + e.getLocalizedMessage());

    }finally {
        if (result != null) {
            result.close();
            result = null;
        }
    }

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Log.e(TAG, e.getMessage());
        }
    }
}
}).start();

DataBaseHelper类:

public class DataBaseHelper extends SQLiteOpenHelper {

    private static final int DATABASE_VERSION = 1;
    public static final String DATABASE_NAME = "YadProjectDB.db";
    public static final String SMS_TABLE_NAME = "sms";
    public static final String SMS_COLUMN_PHONE_NUMBER = "number";
    public static final String SMS_COLUMN_SMS_TEXT = "message";

    public static final String BLACK_LIST_TABLE_NAME = "blackList";
    public static final String BLACK_LIST_COLUMN_ID = "id";
    public static final String BLACK_LIST_COLUMN_PHONE_NUMBER = "number";

    private final String TAG = "DataBaseHelper";

    public DataBaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);

    }

    @Override
    public void onCreate( SQLiteDatabase db ) {
        String command = "CREATE TABLE "
                + SMS_TABLE_NAME
                + "("
                + SMS_COLUMN_PHONE_NUMBER + " TEXT,"
                + SMS_COLUMN_SMS_TEXT + " TEXT,"
                + ")";
        try {
            db.execSQL(command);
        }catch (Exception e) {
            Log.e(TAG, "err->" + e.getMessage());
        }

        command = "CREATE TABLE "
                + BLACK_LIST_TABLE_NAME
                + "("
                + BLACK_LIST_COLUMN_PHONE_NUMBER + " TEXT,"
                + ")";
        try {
            db.execSQL(command);
        }catch (Exception e) {
            Log.e(TAG, "err->" +  e.getMessage());
        }
    }

    public boolean insertToSms(String number, String message, String fileName, Integer uploadFlag, Integer blackList, Integer pictureFlag)
    {
        final SQLiteDatabase db = this.getWritableDatabase();
        ContentValues contentValues = new ContentValues();
        contentValues.put(SMS_COLUMN_PHONE_NUMBER, number);
        contentValues.put(SMS_COLUMN_SMS_TEXT, message);
        try {
            db.insert(SMS_TABLE_NAME, null, contentValues);
            return true;
        }catch (Exception e) {
            Log.e(TAG, "err->" + e.getMessage());
            return false;
        }
    }

    public Cursor getData(String query){
        final SQLiteDatabase db = getReadableDatabase();
        Cursor res = null;
        try {
            res = db.rawQuery(query, null);
            res.moveToFirst();
            return res;
        }catch (Exception e) {
            Log.e(TAG, "err->" + e.getMessage());
            if (res != null) {
                res.close();
                res = null;
            }
        }
        return null;
    }
}

1
导致这些异常的原因并找出问题。 - Shervin Gharib
好的,为什么要遍历游标? - pskink
正如您所看到的,我正在检索每一行的数据(例如电话号码)。 - Shervin Gharib
请检查您的Activity中是否存在任何泄漏:似乎由于内存不足,无法分配CursorWindow。 - pskink
这是您自己的数据库,因此您知道何时插入/更新/删除任何内容,不是吗? - pskink
显示剩余4条评论
1个回答

10

这看起来与SQLite Android数据库游标窗口分配失败2048kb的问题相同。

你的错误提示为:"打开Cursors"

上述问题中的答案解释了原因:

最常见的原因是未关闭的游标。确保在使用完游标后关闭它们(即使出现错误的情况下也是如此)。

Cursor cursor = null;
try {
    cursor = db.query(...
    // do some work with the cursor here.
} finally {
    // this gets called even if there is an exception somewhere above
    if(cursor != null)
        cursor.close();
}

正如您所看到的,我正在正确关闭游标。 - Shervin Gharib
1
你的应用程序中其他地方的游标怎么样?你可能在其他地方泄漏了它们。 - ByteWelder
我在其他线程中使用相同的代码,但逻辑不同。那么其他异常呢? - Shervin Gharib
1
还有其他例外吗? 你是否泄漏了其他数据?可能有一些数据被保存在内存中,并不断增长,直到5-6个小时后变得过多,导致下一个分配(光标创建)失败。 - ByteWelder
我正在使用收到的短信填充数据库并对其进行一些操作。我在没有任何短信和空数据库的情况下测试了应用程序,但仍然出现相同的异常。 - Shervin Gharib
异常只涉及数据库相关问题。 - Shervin Gharib

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接