搜索
您的当前位置:首页正文

CursorWindow OOM

来源:二三娱乐

错误信息

08-30 20:27:36.751 E/CursorWindow(  760): Could not allocate CursorWindow '/data/data/com.android.providers.media/databases/external.db' of size 2097152 due to error -12.
08-30 20:27:36.771 E/JavaBinder(  760): *** Uncaught remote exception!  (Exceptions are not yet supported across processes.)
08-30 20:27:36.771 E/JavaBinder(  760): android.database.CursorWindowAllocationException: Cursor window allocation of 2048 kb failed. # Open Cursors=781 (# cursors opened by pid 3105=781)
08-30 20:27:36.771 E/JavaBinder(  760):  at android.database.CursorWindow.<init>(CursorWindow.java:104)
08-30 20:27:36.771 E/JavaBinder(  760):  at android.database.AbstractWindowedCursor.clearOrCreateWindow(AbstractWindowedCursor.java:198)
08-30 20:27:36.771 E/JavaBinder(  760):  at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:162)
08-30 20:27:36.771 E/JavaBinder(  760):  at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:156)
08-30 20:27:36.771 E/JavaBinder(  760):  at android.database.CursorToBulkCursorAdaptor.count(CursorToBulkCursorAdaptor.java:184)
08-30 20:27:36.771 E/JavaBinder(  760):  at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:117)
08-30 20:27:36.771 E/JavaBinder(  760):  at android.os.Binder.execTransact(Binder.java:338)
08-30 20:27:36.771 E/JavaBinder(  760):  at dalvik.system.NativeStart.run(Native Method)

错误原因

CursorWindow缓存数据达到最大限制(2M不同的机器和SQLite版本其值可能不同)后,仍有查询结果集需要缓存,在申请内存分配时申请失败发生了OOM内存溢出;SQLite查询出的数据集cursor,都由native层的CursorWindow进行数据管理,包括内存空间的申请和数据的填充。CursorWindow实际上是共享内存的抽象,以实现跨进程,跨应用数据共享(ContentProvider作为数据通道,也支持跨进程,跨应用的数据访问)
在ContentProvider端透过SQLiteDatabase的封装查询到的数据集保存在CursorWindow所指向的共享内存中,然后通过Binder把这片共享内存传递到ContentResolver端,即查询端。这样客户就可以通过Cursor来访问这块共享内存中的数据集了。

解决办法

     Cursor c;
     try { 
         c = queryCursor(); 
         int a = c.getInt(1); 
         ......
         // 如果出错,后面的cursor.close()将不会执行
         //c.close(); 
     } catch (Exception e) { 
     } finally{
         if (c != null) {
             c.close();
         }
     } 

如果你的Cursor需要在Activity的不同的生命周期方法中打开和关闭,那么一般可以这样做:
在onCreate()中打开,在onDestroy()中关闭;
在onStart() 中打开,在onStop() 中关闭;
在onResume()中打开,在onPause() 中关闭;
即要在成对的生命周期方法中打开/关闭

如果程序中使用了CursorAdapter(例如Music),那么可以使用它的changeCursor(Cursor cursor)方法同时完成关闭旧Cursor使用新Cursor的操作。

Top