美文网首页
CursorWindow OOM

CursorWindow OOM

作者: 客舟求简 | 来源:发表于2016-10-30 22:50 被阅读374次

    错误信息

    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来访问这块共享内存中的数据集了。

    解决办法

    保证CursorWindow不会达到最大限制):
    1.只查询需要的字段;
    根据UI显示需要,或实际需要查询的字段进行查询,尽量不会表查询
    2.二进制文件不要存在数据库中;
    数据库仅适用于保存一些较短文字,整数,布尔,浮点数等一些,易于查询和操作的轻量级的数据,目的也是在于快速搜索和查询。对于像图片,较长的文字(如文章)等大数据,最好直接以文件形式存储在硬盘中,然后在数据库保存它们的访问路径
    3.对于大数据量的查询采用分段查询方式;
    无论表中的一条记录数据量如何的小,当条数达到5000级或者万级或者更多的时候,还是会达到最大的限制
    4.正确的关闭Cursor,释放CursorWindow中不用的资源(需手动调用释放native中的资源,类似3.0之前的Bitmap需要手动释放。调用close的必要性:http://www.jianshu.com/p/3b433ed25aaf

         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的操作。

    相关文章

      网友评论

          本文标题:CursorWindow OOM

          本文链接:https://www.haomeiwen.com/subject/grbuuttx.html