從源碼看Android中sqlite是怎麼讀DB的

來源:互聯網
上載者:User

標籤:

執行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 //AbstractCursor11 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 //AbstractWindowedCursor28 29 /** @hide */30 @Override31 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 //SQLiteClosable46 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 //CursorWindow62 63 @Override64 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)泄露。

 

 

從源碼看Android中sqlite是怎麼讀DB的

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.