更多内容在这里查看 
https://ahangchen.gitbooks.io/windy-afternoon/content/

执行QUERY

执行SQLiteDatabase类中query系列函数时,只会构造查询信息,不会执行查询。

(query的源码追踪路径)

执行MOVE(里面的FILLWINDOW是真正打开文件句柄并分配内存的地方)

当执行Cursor的move系列函数时,第一次执行,会为查询结果集创建一块共享内存,即cursorwindow

moveToPosition源码路径

FILLWINDOW—-真正耗时的地方

然后会执行sql语句,向共享内存中填入数据,

fillWindow源码路径

在SQLiteCursor.Java中可以看到

@Override
public boolean onMove(int oldPosition, int newPosition) {// Make sure the row at newPosition is present in the windowif (mWindow == null || newPosition < mWindow.getStartPosition() ||newPosition >= (mWindow.getStartPosition() + mWindow.getNumRows())) {fillWindow(newPosition);}return true;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

如果请求查询的位置在cursorWindow的范围内,不会执行fillWindow,

而超出cursorwindow的范围,会调用fillWindow,

而在nativeExecuteForCursorWindow中,

获取记录时,如果要请求的位置超出窗口范围,会发生CursorWindow的清空:

CopyRowResult cpr = copyRow(env, window, statement, numColumns, startPos, addedRows);
if (cpr == CPR_FULL && addedRows && startPos + addedRows < requiredPos) {
// We filled the window before we got to the one row that we really wanted.
// Clear the window and start filling it again from here.
// TODO: Would be nicer if we could progressively replace earlier rows.
window->clear();
window->setNumColumns(numColumns);
startPos += addedRows;
addedRows = 0;
cpr = copyRow(env, window, statement, numColumns, startPos, addedRows);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

CursorWindow的清空机制会影响到多线程读(通常认为不可以并发读写,sqlite的并发实际上是串行执行的,但可以并发读,这里要强调的是多线程读也可能有问题),具体见稍后一篇文章“listview并发读写数据库”。

上面说的这些直观的感受是什么样的呢?大概是这样,

执行query,读10000条数据,很快就拿到了cursor,这里不会卡,

执行moveToFirst,卡一下(fillwindow(0))

moveToPosition(7500),卡一下,因为已经超了cursorwindow的区域,又去fillwindow(7500),

关于fillwindow还有一些奇特的细节,比如4.0以后,fillwindow会填充position前后各一段数据,防止读旧数据的时候又需要fill,感兴趣的同学可以看看各个版本fillwidow的源码。

这里还可以延伸一下,因为高版本的Android sqlite对旧版有许多改进,

所以实际开发里我们有时候会把sqlite的源码带在自己的工程里,使得低版本的android也可以使用高版本的特性,并且避开一部分兼容性问题。

CURSOR关闭(显式调用CLOSE()的理由)

追踪源码看关闭

 //SQLiteCursorsuper.close();
synchronized (this) {mQuery.close();mDriver.cursorClosed();
}//AbstractCursorpublic void close() {mClosed = true;mContentObservable.unregisterAll();onDeactivateOrClose();
}protected void onDeactivateOrClose() {if (mSelfObserver != null) {mContentResolver.unregisterContentObserver(mSelfObserver);mSelfObserverRegistered = false;}mDataSetObservable.notifyInvalidated();
}//AbstractWindowedCursor/** @hide */
@Override
protected void onDeactivateOrClose() {super.onDeactivateOrClose();closeWindow();
}protected void closeWindow() {if (mWindow != null) {mWindow.close();mWindow = null;}
}//SQLiteClosablepublic void close() {releaseReference();
}public void releaseReference() {boolean refCountIsZero = false;synchronized(this) {refCountIsZero = --mReferenceCount == 0;}if (refCountIsZero) {onAllReferencesReleased();}
}//CursorWindow@Override
protected void onAllReferencesReleased() {dispose();
}private void dispose() {if (mCloseGuard != null) {mCloseGuard.close();}if (mWindowPtr != 0) {recordClosingOfWindow(mWindowPtr);nativeDispose(mWindowPtr);mWindowPtr = 0;}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77

跟CursorWindow有关的路径里,最终调用nativeDispose()清空cursorWindow;

当Cursor被GC回收时,会调用finalize:

@Override
protected void finalize() {try {// if the cursor hasn't been closed yet, close it firstif (mWindow != null) {if (mStackTrace != null) {String sql = mQuery.getSql();int len = sql.length();StrictMode.onSqliteObjectLeaked("Finalizing a Cursor that has not been deactivated or closed. " +"database = " + mQuery.getDatabase().getLabel() +", table = " + mEditTable +", query = " + sql.substring(0, (len > 1000) ? 1000 : len),mStackTrace);}close();}} finally {super.finalize();}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

然而finalize()并没有释放CursorWindow,而super.finalize();里也只是解绑了观察者,没有去释放cursorwindow

所以不调用cursor.close(),最终会导致cursorWindow所在的共享内存(1M或2M)泄露。

原文地址http://blog.csdn.net/u011453773/article/details/50731250

从源码看ANDROID中SQLITE是怎么通过CURSORWINDOW读DB的相关推荐

  1. dlsym 如何查看一个so里面的_Android so 文件进阶二 从dlsym()源码看android 动态链接过程...

    0x00  前言 这篇文章其实是我之前学习elf文件关于符号表的学习笔记,网上也有很多关于符号表的文章,怎么说呢,感觉像是在翻译elf文件格式的文档一样,千篇一律,因此把自己的学习笔记分享出来.dls ...

  2. 从源码解析-Android中Zygote进程是如何fork一个APP进程的

    zygote进程fork子进程 前言 强烈推荐 进程创建流程 APP启动第三方应用 startActivity startService sendBroadcast ContentResolver.q ...

  3. 从源码解析-Android中View的绘制流程及performTraversals方法

    谈谈Activity的setContentView是怎么加载XML视图的 谈谈Activity的View怎么与View绘制工具ViewRootImpl关联的 在前面两篇文章中分析了View是如何跟绘制 ...

  4. 从源码看DL4J中Native BLAS的加载,以及配置

    最近在用DeepLearning4J(DL4J)尝试语音识别的深度学习,git DL4J的代码,用IntelliJ IDEA打开,配置好相关依赖后,运行包org.deeplearning4j.exam ...

  5. 【Android 安装包优化】p7zip 源码交叉编译 Android 平台可执行程序 ( 下载 p7zip 源码 | 交叉编译 Android 中使用 7z 可执行程序 )

    文章目录 一.下载 p7zip 源码 二.交叉编译 Android 中使用 7z 可执行程序 三.参考资料 一.下载 p7zip 源码 下载 7zip 源码 , 下载页面 https://source ...

  6. 从AndFix源码看Android热修复

    前几篇文章介绍过注入Dex实现热修复:http://blog.csdn.net/u011686167/article/details/78966936 .现在探讨阿里系的底层替换虚拟机的方法指针实现热 ...

  7. android 代码 drawable,Android Drawable完全解析(一):Drawable源码分析(中)

    呃...我不是故意要凑篇幅写个什么上下篇,实在是因为Drawable源码有点长,一篇写不下啦O(∩_∩)O~ 鉴于源码一般较长,以后所有源码分析的部分,英文注释非必要情况都不再保留! 2:Drawab ...

  8. 结合源码探讨Android系统的启动流程

    结合源码探讨Android系统的启动流程 由于本人能力有限,所考虑或者疏忽错漏的地方或多或少应该存在.同时,Android从启动过程开始,实际上就涉及多个技术难点和多种通信机制的知识点. 基于上面两个 ...

  9. 视频直播源码在Android端实现1对1音视频实时通话

    我们要使用 WebRTC 进行音视频互动时需要申请访问硬件的权限,至少要申请以下三种权限 Camera 权限 Record Audio 权限 Intenet 权限 在Android中,申请权限分为静态 ...

最新文章

  1. Kotlin 类的定义
  2. java防止用户越权访问文件_针对功能权限(url访问)如何避免越权访问
  3. 实现windows标准的选择文件夹功能
  4. rep movsd + rep movsb 内联实现 strcpy
  5. 【人物】徐小平:远离创业的3个死亡陷阱
  6. 使用websockets,后台实时发数据,前台实时接受数据,并集成到Django
  7. OpenCV视频进度播放控制
  8. PreparedStatement跟Statement的对比
  9. 智能玩具 数据采集 首页展示 注册 登录 自动登录 二维码图片
  10. 【老军医方】在脱发过程中遇到的各种疑难杂症
  11. WIFI抓包理论篇——802.11帧与EthernetII帧的差别
  12. marlab中主成分得分怎么求_数学无耻得分法,独家秘密,快点用起来
  13. esp8266开发入门教程(基于Arduino)——环境安装
  14. Redis 3种集群方式,别傻傻分不清!
  15. 耳麦没声音,耳麦不能说话
  16. Shave Beaver! CodeForces - 331B2 (线段树)
  17. Clickhouse 各种工具函数知识 -<日期函数>
  18. 中国移动号码手机开机以及注册gprs流程(转载)
  19. 物联网技能大赛-Ubuntu-(4)
  20. python numpy.arry, pytorch.Tensor及原生python中list相互转换

热门文章

  1. 雷达模拟器-监控摄像机模拟软件 SPx Video Simulator
  2. A-level 课程:最受欢迎和最不受欢迎的学科
  3. pyinstaler打包paddle
  4. Java动态性——反射机制学习笔记
  5. 轻便易用的三维建模软件
  6. canvas绘制火柴人
  7. Django报错 ValueError: The view didn‘t return an HttpResponse object. It returned None instead.
  8. 如何自定义您的Nintendo Switch主屏幕
  9. 揭秘:雷电模拟器工作方式
  10. 深井泵房无人值守系统 泵站无人值守平台 智慧水务