【问题标题】:Cursor window allocation of 2048 kb failed. # Open Cursors=1 (# cursors opened by this proc=1)2048 kb 的光标窗口分配失败。 # Open Cursors=1 (# 此过程打开的游标=1)
【发布时间】:2015-09-30 10:24:20
【问题描述】:

我正在制作一个使用数据库的 Kiosk 应用程序。该应用程序一直在前台运行。该应用程序有许多线程使用一个共享的 DataBaseHelper 实例。该应用程序完美无缺,但大多数时候在 5 或 6 小时后,我遇到这些异常然后应用程序崩溃:

E/DataBaseHelper: 2048 kb 的光标窗口分配失败。 # 打开 Cursors=1(此 proc=1 打开的 # 个游标)

E/CursorWindow﹕无法分配 CursorWindow '/data/user/0/com.kios.frm/databases/YadProjectDB.db' 的 由于错误 -24,大小为 2097152。

E/SQLiteLog: (14) 无法在 [00bb9c9ce4] 的第 30192 行打开文件

E/SQLiteLog: (14) 语句在 16 处中止:[SELECT number FROM sms LIMIT 5] 无法打开数据库文件

E/SQLiteQuery﹕异常:无法打开数据库文件(代码 14);
查询:SELECT number FROM sms LIMIT 5

E/SQLiteLog﹕(14) os_unix.c:30192: (24)
打开(/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;
    }
}

【问题讨论】:

  • 你到底想达到什么目的?
  • 这些异常的原因并找出问题
  • 好的,你为什么要遍历光标?
  • 如您所见,我正在检索每一行的数据(如 phoneNumber)。
  • 检查您的 Activity 中是否有任何泄漏:由于内存不足,CursorWindow 似乎无法分配

标签: android database android-sqlite android-4.4-kitkat android-cursor


【解决方案1】:

这看起来与SQLite Android Database Cursor window allocation of 2048 kb failed 相同的问题

您的错误提示:“打开光标”

上述问题的答案说明了这一点:

大多数情况下,导致此错误的原因是未关闭的游标。确保 使用后关闭所有游标(即使出现错误)。

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

【讨论】:

  • 如您所见,我正在正确关闭光标
  • 那么游标在你的应用程序的其他地方呢?您可能会将它们泄漏到其他地方。
  • 我在其他线程中使用相同的代码,但逻辑不同。其他例外情况呢?
  • 还有什么例外?您是否泄露了任何其他数据?您可能会在内存中保留某种数据并继续增长直到 5-6 小时,当它变得太多并且您的下一次分配(游标创建)失败时。
  • 我正在用传入的短信填充数据库并对它们进行一些操作。我测试了没有任何短信和空数据库的应用程序,再次发生相同的异常。
猜你喜欢
  • 2012-07-05
  • 2013-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-26
  • 1970-01-01
  • 2015-03-25
相关资源
最近更新 更多