从源码看Android中sqlite是怎么读DB的(转)
执行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的(转)的更多相关文章
- 从源码看Android中sqlite是怎么通过cursorwindow读DB的
更多内容在这里查看 https://ahangchen.gitbooks.io/windy-afternoon/content/ 执行query 执行SQLiteDatabase类中query系列函数 ...
- Android so 文件进阶<二> 从dlsym()源码看android 动态链接过程
0x00 前言 这篇文章其实是我之前学习elf文件关于符号表的学习笔记,网上也有很多关于符号表的文章,怎么说呢,感觉像是在翻译elf文件格式的文档一样,千篇一律,因此把自己的学习笔记分享出来.dls ...
- 源码解析Android中View的measure量算过程
Android中的Veiw从内存中到呈现在UI界面上需要依次经历三个阶段:量算 -> 布局 -> 绘图,关于View的量算.布局.绘图的总体机制可参见博文< Android中View ...
- 从源码看java中Integer的缓存问题
在开始详细的说明问题之前,我们先看一段代码 public static void compare1(){ Integer i1 = 127, i2 = 127, i3 = 128, i4 = 128; ...
- 从源码看 Vue 中的 Mixin
最近在做项目的时候碰到了一个奇怪的问题,通过 Vue.mixin 方法注入到 Vue 实例的一个方法不起作用了,后来经过仔细排查发现这个实例自己实现了一个同名方法,导致了 Vue.mixin 注入方法 ...
- 从 php 源码看 php 中的对象
从一个简单的例子说起: class Person { public $name; public $age; public function __construct($name, $age) { $th ...
- 将Android源码导入eclipse中的方法以及编译Android源码指定模块
本文博客地址:http://blog.csdn.net/qq1084283172/article/details/53365659 将android源码导入eclipse.androidstudio. ...
- 从微信小程序开发者工具源码看实现原理(一)- - 小程序架构设计
使用微信小程序开发已经很长时间了,对小程序开发已经相当熟练了:但是作为一名对技术有追求的前端开发,仅仅熟练掌握小程序的开发感觉还是不够的,我们应该更进一步的去理解其背后实现的原理以及对应的考量,这可能 ...
- 从源码看commit和commitAllowingStateLoss方法区别
Fragment介绍 在很久以前,也就是我刚开始写Android时(大约在2012年的冬天--),那时候如果要实现像下面微信一样的Tab切换页面,需要继承TabActivity,然后使用TabHost ...
随机推荐
- 打开 chm 帮助文件显示空白及解决方法
有个很奇葩的解决方法:把 chm 文件用压缩软件压缩,然后用压缩软打开此压缩包,直接双击压缩包里面的 chm 文件 这虽然解决了问题,但是这不科学…… 分析:直接打开压缩包里面的文件,压缩包的文件是临 ...
- Java 的swing.GroupLayout布局管理器的使用方法和实例(转)
The following builds a panel consisting of two labels in one column, followed by two textfields in t ...
- async And await异步编程活用基础
原文:async And await异步编程活用基础 好久没写博客了,时隔5个月,奉上一篇精心准备的文章,希望大家能有所收获,对async 和 await 的理解有更深一层的理解. async 和 a ...
- Android Application Thread CPU GC Operatiing and OOM Question 0603-随手笔记
面前app当完成测试,没问题,以完成整个老龄化阶段包含数据收发器,关键在 adb shell top -m 5 我发现我的 app pid 占用 CPU是最多的,事实上我想说写一个app是不难,你 ...
- 解决Fedora升级时nvidia显卡问题
升级到新版Fedora后登录不了gnome 小编最近升级了Fedora 20到21,结果就如之前从Fedora 19升级到20时类似,又出问题了.Fedora你到底行不行... gnome登录不了 ...
- 开源Math.NET基础数学类库使用(05)C#解析Delimited Formats数据格式
原文:[原创]开源Math.NET基础数学类库使用(05)C#解析Delimited Formats数据格式 开源Math.NET基础数学类库使用系列文章总目录: 1.开源.NET基础数学计算组件 ...
- 2015最新iherb海淘攻略-图文入门教程
IHerb是美国最热门的海淘海购网站之中的一个,适合不爱担心,怕麻烦的朋友入门海淘,由于它有中文页面,可直邮中国,上千个母婴用品.化妆品.保健品品牌,最重要的是!首次下单,价值$40及以上的订单会马上 ...
- linux内存操作--ioremap和mmap学习笔记
最近做一些相关的视频输出,对于保留framebuffer内存使用情况不是很清楚,现在找了一些资料整理出,准备使用.if (希望看到使用) goto 用法: 对于一个系统来讲,会有非常多的外设,那 ...
- linux shell 不同进制数据转换(二进制,八进制,十六进制,base64) (转)
shell可以在不调用第3方命令,表示不同进制数据.这里总结以下表示方法.shell 脚本默认数值是由10 进制数处理,除非这个数字某种特殊的标记法或前缀开头. 才可以表示其它进制类型数值.如:以 0 ...
- j经常使用ava应用server
什么是应用server它?它主要提供的执行环境的应用程序,为组件提供服务. 要了解更多关于,您可以查看我的博客:何为容器? Java 的应用server非常多,从功能上分为两类:WEB 应用serve ...