跑 SQLite 查询不及时使用 sqlite3_finalize() 的严重后果,望周知。

本事件已被我投稿至纯靠北工程师(「#純靠北工程師 7ib 」)。

教训是:用 SQLite 跑完「每一笔」查询之后一定要「立刻」用 sqlite3_finalize(StatementPointer) 释放运存,不然会产生连 Xcode Instruments 都抓不到的运存泄漏。

事情是这样:

为了因应 Apple 对 8GB 运存的病态执着, 我最近刚刚给威注音输入法的原厂词库格式由 JSON 升级至 SQLite 。

我是第一次用 SQLite ,看这篇学的(威注音是用 Swift 开发的): itisjoe.gitbooks.io/swiftgo/con... 现在 Swift 用 SQLite 超方便,直接 import SQLite3 就行。 ( Linux 或者旧版 macOS 还可以直接读 SQLite3 的 almagation 。) 只是,窃以为我犯的最大错误就是「没有针对相关的 SQLite API 详读 SQLite 官方的手册」。

我一开始以为让所有的 SQLite Statement 共用一个(作为静态变数的) nullable OpaquePointer 就可以了, 于是我一开始的设计就是让辞典模组在 deinit() 的时候才跑一次「 sqlite3_finalize()」。 因为原厂词库是只读的、在 App Bundle 内,所以我将 journal 塞在了运存内。

结果呢?施工完毕之后,单元测试啥的都成功通过了,刚刚开启输入法时的运存占用是 18MB 左右。 当时我感觉很开心,因为这几乎是直接消灭了输入法启动时花在原厂辞典上的载入时间。 但是,周一上午,我用这输入法没打六分钟的字,输入法碰到了我之前设定的保险丝而自尽了: 我早前做了这么个保险设计:只要运存占用超过 768MB ,输入法就自尽、自动重新启动来释放运存。

然后,我用 Xcode 14.2 的 Instruments 抓运存泄漏, 但只抓到一个与系统输入法选单有关的小微型泄漏(还是无法解决的那种)。 正好我周一那天公司休假,我花了一整个周一的时间排查自己做过的所有修改, 最后开始怀疑「 sqlite3_finalize()」是不是得在每次查询之后都执行一次。 于是我补上了这句试了试:

swift 复制代码
extension vChewingLM.LMInstantiator {
  fileprivate static func querySQL(strStmt sqlQuery: String, coreColumn column: CoreColumn, handler: (String) -> Void) {
    guard Self.ptrSQL != nil else { return }
    defer { sqlite3_finalize(Self.ptrStatement) } // 补上了这句。
    sqlite3_prepare_v2(Self.ptrSQL, sqlQuery, -1, &Self.ptrStatement, nil)
    while sqlite3_step(Self.ptrStatement) == SQLITE_ROW {
      guard let rawValue = sqlite3_column_text(Self.ptrStatement, column.id) else { continue }
      handler(String(cString: rawValue))
    }
  }
...
}

结果发现运存泄漏的问题失踪了。 这问题幸好发现得早,不然威注音 3.6.2 正式版带着这个 Bug 发出去的话会坑死很多人。

然后我就将这次经历投稿到靠北工程师,但没想到反应非常空前。 居然还有人说我积阴德。还有人在转发时提到这么个例子:

超市的系统在频繁的查询资料后都会有整个系统延迟的状况,不知道跟这有没关系... 虽然资料库跟我没啥屁关系,也先备份再说。

于是我决定将这个故事也放在掘金这边让各位 SQLite 用户共勉。

相关推荐
时差95331 分钟前
【面试题】Hive 查询:如何查找用户连续三天登录的记录
大数据·数据库·hive·sql·面试·database
让学习成为一种生活方式33 分钟前
R包下载太慢安装中止的解决策略-R语言003
java·数据库·r语言
秋意钟1 小时前
MySQL日期类型选择建议
数据库·mysql
Dxy12393102162 小时前
python下载pdf
数据库·python·pdf
桀桀桀桀桀桀2 小时前
数据库中的用户管理和权限管理
数据库·mysql
superman超哥4 小时前
04 深入 Oracle 并发世界:MVCC、锁、闩锁、事务隔离与并发性能优化的探索
数据库·oracle·性能优化·dba
用户8007165452004 小时前
HTAP数据库国产化改造技术可行性方案分析
数据库
engchina4 小时前
Neo4j 和 Python 初学者指南:如何使用可选关系匹配优化 Cypher 查询
数据库·python·neo4j
engchina4 小时前
使用 Cypher 查询语言在 Neo4j 中查找最短路径
数据库·neo4j
尘浮生4 小时前
Java项目实战II基于Spring Boot的光影视频平台(开发文档+数据库+源码)
java·开发语言·数据库·spring boot·后端·maven·intellij-idea