执行query

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

(query的源码追踪路径)

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

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

moveToPosition源码路径

fillWindow----真正耗时的地方

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

fillWindow源码路径

在SQLiteCursor.java中可以看到

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

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

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

而在nativeExecuteForCursorWindow中,

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

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

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

Cursor关闭(显式调用close()的理由)

追踪源码看关闭

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

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

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

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

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

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

http://www.cnblogs.com/hellocwh/p/4924732.html

从源码看Android中sqlite是怎么读DB的(转)的更多相关文章

  1. 从源码看Android中sqlite是怎么通过cursorwindow读DB的

    更多内容在这里查看 https://ahangchen.gitbooks.io/windy-afternoon/content/ 执行query 执行SQLiteDatabase类中query系列函数 ...

  2. Android so 文件进阶<二> 从dlsym()源码看android 动态链接过程

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

  3. 源码解析Android中View的measure量算过程

    Android中的Veiw从内存中到呈现在UI界面上需要依次经历三个阶段:量算 -> 布局 -> 绘图,关于View的量算.布局.绘图的总体机制可参见博文< Android中View ...

  4. 从源码看java中Integer的缓存问题

    在开始详细的说明问题之前,我们先看一段代码 public static void compare1(){ Integer i1 = 127, i2 = 127, i3 = 128, i4 = 128; ...

  5. 从源码看 Vue 中的 Mixin

    最近在做项目的时候碰到了一个奇怪的问题,通过 Vue.mixin 方法注入到 Vue 实例的一个方法不起作用了,后来经过仔细排查发现这个实例自己实现了一个同名方法,导致了 Vue.mixin 注入方法 ...

  6. 从 php 源码看 php 中的对象

    从一个简单的例子说起: class Person { public $name; public $age; public function __construct($name, $age) { $th ...

  7. 将Android源码导入eclipse中的方法以及编译Android源码指定模块

    本文博客地址:http://blog.csdn.net/qq1084283172/article/details/53365659 将android源码导入eclipse.androidstudio. ...

  8. 从微信小程序开发者工具源码看实现原理(一)- - 小程序架构设计

    使用微信小程序开发已经很长时间了,对小程序开发已经相当熟练了:但是作为一名对技术有追求的前端开发,仅仅熟练掌握小程序的开发感觉还是不够的,我们应该更进一步的去理解其背后实现的原理以及对应的考量,这可能 ...

  9. 从源码看commit和commitAllowingStateLoss方法区别

    Fragment介绍 在很久以前,也就是我刚开始写Android时(大约在2012年的冬天--),那时候如果要实现像下面微信一样的Tab切换页面,需要继承TabActivity,然后使用TabHost ...

随机推荐

  1. 打开 chm 帮助文件显示空白及解决方法

    有个很奇葩的解决方法:把 chm 文件用压缩软件压缩,然后用压缩软打开此压缩包,直接双击压缩包里面的 chm 文件 这虽然解决了问题,但是这不科学…… 分析:直接打开压缩包里面的文件,压缩包的文件是临 ...

  2. Java 的swing.GroupLayout布局管理器的使用方法和实例(转)

    The following builds a panel consisting of two labels in one column, followed by two textfields in t ...

  3. async And await异步编程活用基础

    原文:async And await异步编程活用基础 好久没写博客了,时隔5个月,奉上一篇精心准备的文章,希望大家能有所收获,对async 和 await 的理解有更深一层的理解. async 和 a ...

  4. Android Application Thread CPU GC Operatiing and OOM Question 0603-随手笔记

    面前app当完成测试,没问题,以完成整个老龄化阶段包含数据收发器,关键在 adb shell top -m 5  我发现我的 app pid 占用  CPU是最多的,事实上我想说写一个app是不难,你 ...

  5. 解决Fedora升级时nvidia显卡问题

    ​ 升级到新版Fedora后登录不了gnome 小编最近升级了Fedora 20到21,结果就如之前从Fedora 19升级到20时类似,又出问题了.Fedora你到底行不行... gnome登录不了 ...

  6. 开源Math.NET基础数学类库使用(05)C#解析Delimited Formats数据格式

    原文:[原创]开源Math.NET基础数学类库使用(05)C#解析Delimited Formats数据格式 开源Math.NET基础数学类库使用系列文章总目录:   1.开源.NET基础数学计算组件 ...

  7. 2015最新iherb海淘攻略-图文入门教程

    IHerb是美国最热门的海淘海购网站之中的一个,适合不爱担心,怕麻烦的朋友入门海淘,由于它有中文页面,可直邮中国,上千个母婴用品.化妆品.保健品品牌,最重要的是!首次下单,价值$40及以上的订单会马上 ...

  8. linux内存操作--ioremap和mmap学习笔记

    最近做一些相关的视频输出,对于保留framebuffer内存使用情况不是很清楚,现在找了一些资料整理出,准备使用.if (希望看到使用)  goto   用法: 对于一个系统来讲,会有非常多的外设,那 ...

  9. linux shell 不同进制数据转换(二进制,八进制,十六进制,base64) (转)

    shell可以在不调用第3方命令,表示不同进制数据.这里总结以下表示方法.shell 脚本默认数值是由10 进制数处理,除非这个数字某种特殊的标记法或前缀开头. 才可以表示其它进制类型数值.如:以 0 ...

  10. j经常使用ava应用server

    什么是应用server它?它主要提供的执行环境的应用程序,为组件提供服务. 要了解更多关于,您可以查看我的博客:何为容器? Java 的应用server非常多,从功能上分为两类:WEB 应用serve ...