• 从源码看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 }
    View Code

    跟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

  • 相关阅读:
    CocoStudio UI 编辑器的使用
    脚本AI与脚本引擎
    Android 开发问题集合
    cocos2d-x之 CCSpriteBatchNode 用法总结
    图解VS2010打包全过程
    如何写详细设计文档
    母函数(Generating function)详解 — TankyWoo
    【DP_区间DP专辑】 zeroclock
    【DP_概率DP专辑】【from zeroclock's blog】
    【DP_树形DP专辑】【from zeroclock's blog】
  • 原文地址:https://www.cnblogs.com/softidea/p/4925285.html
Copyright © 2020-2023  润新知