更多内容在这里查看

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 window
if (mWindow == null || newPosition < mWindow.getStartPosition() ||
newPosition >= (mWindow.getStartPosition() + mWindow.getNumRows())) {
fillWindow(newPosition);
} return true;
}

如果请求查询的位置在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);
}

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()的理由)

追踪源码看关闭

  //SQLiteCursor

 super.close();
synchronized (this) {
mQuery.close();
mDriver.cursorClosed();
} //AbstractCursor public 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;
}
} //SQLiteClosable public 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;
}
}

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

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

 @Override
protected void finalize() {
try {
// if the cursor hasn't been closed yet, close it first
if (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();
}
}

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

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

从源码看Android中sqlite是怎么通过cursorwindow读DB的的更多相关文章

  1. 从源码看Android中sqlite是怎么读DB的(转)

    执行query 执行SQLiteDatabase类中query系列函数时,只会构造查询信息,不会执行查询. (query的源码追踪路径) 执行move(里面的fillwindow是真正打开文件句柄并分 ...

  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. [Linked List]Linked List Cycle,Linked List Cycle II

    一.Linked List Cycle Total Accepted: 85115 Total Submissions: 232388 Difficulty: Medium Given a linke ...

  2. js & jq 加载js

    最近做项目中, 经常要写js代码的, 从纯前端人员, 到我们这边的过度, 每个人写的风格都不一样, 大概整理了一下有这么几种 1.1 $(document).ready(function(){}); ...

  3. putty修改编码

    在窗口标题上点击右键,选择 Change Settings... 在打开的配置窗口左边选择 Appearance,在右边点 Font settings 里面的 Change 按钮,选择好中文字体,比如 ...

  4. UML中的交互图<转>

      转自>>http://blog.csdn.net/mingxuanyun/article/details/8572128 交互图用来描述系统中的对象是如何进行相互作用的,即一组对象是如 ...

  5. 解决jquery zclip 插件点击无效的问题

    使用jquery zclip 用于页面复制文本内容. 首先引入js <script type="text/javascript" src="../js/jquery ...

  6. php 截取字符串

    /** * 方法库-截取字符串-[该函数作者未知] * @param string $string 字符串 * @param int $length 字符长度 * @param string $dot ...

  7. Delphi常见图象格式转换技术

    TJPEGScale = (jsFullSize, jsHalf, jsQuarter, jsEighth);//图片大小(全部,1/2,1/4,1/8)TBitmap.pixelFormat:=pf ...

  8. 只有电信3G是公网ip。

    只有电信3G是公网ip,其它网络拿到是内部网.

  9. SEO高手在扯蛋?

    真正的高手SEO你在扯蛋吗?当大家都很会扯的时候,高手扯得肯定比你疼,不是他们 蛋比较敏感,而是他们的确更用力. 当你说我是SEO时,高手肯定说现在我在做的是SEM. 当你说我是SEM时,高手肯定在说 ...

  10. SQL Server数据库---》基础

    SQL Server:只是操作数据库的一个工具(这种工具,只是提供一个界面化的方式让用户方便操作数据库) 开启服务:点击:我的电脑(计算机)--管理--服务和应用程序--服务--开启SQL Serve ...