当前位置: 首页 > 知识库问答 >
问题:

TimeoutException:net。sqlcipher。数据库SQLiteCompiledSql。finalize()在10秒后超时(Android)

施景同
2023-03-14

在我的android应用程序中,我使用带有sqlcipher库的Room进行加密/解密。我经常在Crashlysis中看到以下崩溃:

java.util.concurrent.超时异常:net.sqlcipher.database.SQLiteCompiledSql.finalize()在sun.misc.Unsafe.park(本地方法)在java.util.concurrent.locks.LockSupport.park(LockSupport.java:190)在java.util.concurrent.locks.AbstractQueuedSynchronizer.park和检查中断(AbstractQueuedSynchronizer.java:868)在java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire排队(AbstractQueuedSynchronizer.java:902)在java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1227)在java.util.concurrent.locks.ReentantLock$FairSync.lock(ReentantLock.java:231)在java. util. conitter. lock。java: 294)在net. sqlciper.数据库。在net. sqlciper. lock(SQLite数据库. java: 567)。SQLiteCompiledSql.释放声明(SQLiteCompiledSql. java: 104)在net. sqlciper.数据库。在java. lang中完成(SQLiteCompiledSql. java: 146)。守护进程$FinazerDaemon. doFinize(Daemons. java: 289)在java. lang。在java. lang上的守护进程$FinazerDaemon. run内部(Daemons. java: 276)。守护进程$Daemon. run(Daemons. java: 137)at java. lang.线程.运行(线程. java: 929)

它崩溃的行是SQLiteDatabase.lock()line 567

以前是第566行,但在该方法中,我插入了一个检查:如果数据库未打开-

我问过sqlcipher的开发人员,但他们不知道是什么导致了这次崩溃。也许有人知道?

共有1个答案

马绪
2023-03-14

我在Crashlytics中看到这一点已经有很长一段时间了,似乎最终能够完全解决这个问题,我将在这里发布完整的研究。

问题

对于类似这样的查询:

@Query("DELETE FROM table WHERE id NOT IN (:ids)")
abstract fun deleteNotInList(ids: List<String>): Int

Room生成不清除游标的代码和生成的语句(在下图中,比较方法one不使用游标和不调用release()方法的方式,与底部调用游标的方法进行比较)。close();方法名称和查询略有不同,因为我简化了代码片段):

在这个场景中,语句保存在内存中,不释放,释放转移到GC阶段,finalize()方法内部。SqlCipher(SQLiteCompiledSql)中的finalize()反过来需要锁定数据库以释放语句:

问题是,数据库可能会被长事务锁定10秒以上(或者是一批较短的事务,使用这种锁定的唤醒顺序是不保证的,也是不公平的)。

GC看门狗在线程达到10/20秒时崩溃,具体取决于OS/JVM的确切版本。

解决方案

是使用IN运算符通过以下手动原始查询重写所有删除/更新:

@RawQuery
abstract fun deleteNotInListRaw(query: SimpleSQLiteQuery): Int

fun deleteNotInList(
    ids: List<String>
) {
    deleteNotInListRaw(
        SimpleSQLiteQuery(
            "DELETE FROM table WHERE id NOT IN (${ids.joinToString(prefix = "'", postfix = "'", separator = "','")})"
        )
    )
}

在这种情况下,查询使用游标,并在删除完成后关闭它,仍然锁定数据库,但不是在GC阶段和专用线程上。

另外,可能有更稳定的长期解决方案,但它们需要在室内/室外实施。

在给定的状态下,可以重构SqlCipher,使其不会在GC阶段锁定数据库。有一个悬而未决的问题:https://github.com/sqlcipher/android-database-sqlcipher/issues/537

Room可能会修复codegen,使用查询生成器并生成语句闭包行,这里没有未解决的问题,但我稍后会再次检查这个想法,并将向他们提出这个问题。

对我们来说,这似乎完全解决了这个问题。

请注意,所有使用IN/NOT-IN运算符的删除/更新查询,以及一些可能阻止Room预编译查询的其他运算符(由于运行时参数),都会导致此问题。您可以检查codegen以验证生成的代码调用了游标。close()语句。release()

 类似资料:
  • 我在Lollipop上收到了奇怪的撞车报告。我的应用程序基本上是一个浏览器,所以它大量使用WebView,但我不知道问题发生在那里。不管怎样,崩溃报告没有提供太多有用的信息,它基本上是我下面粘贴的内容: 有人见过这个吗?知道是什么引起的吗? 编辑:我应该提到的是,这种情况发生在我已经使用了大约10个月的应用程序上,它一直只针对4.0设备。该漏洞仅在5.0设备上报告,上面的stacktrace是Pl

  • 我们公司的应用程序遇到了崩溃,但这个问题不一定存在,我现在无法重现这个问题,我们可以为我提供下一个解决方案的想法 id.finalize()id是RandomAccessFile的子类。 此堆栈跟踪是:

  • 我正在写一个php脚本,它访问远程服务器上的csv文件,处理数据,然后将数据写入本地MySQL数据库。因为要处理和插入数据库的数据太多(50000行),所以脚本运行时间超过60秒。我的问题是,脚本在60秒后超时。 为了确保这不是MySQL的问题,我创建了另一个进入无限循环的脚本,它也会在60秒时超时。 我尝试增加/更改Ubuntu服务器上的以下设置,但没有帮助:max_execution_time

  • 我正在运行一个Nginx PHP-FPM服务器,我有一个脚本,应该在30分钟内执行。240秒后,它停止工作,并从Nginx返回502网关错误。 执行的PHP-FPM日志: [03-May-2013 19:52:02]警告:[池www]child 2949,脚本'/var/www/shell/import_db。php'(请求:“GET/shell/import_db.php”)执行超时(239.9

  • 我们在和PlainSocketImpl。完成。其中90%发生在Android 4.3上。我们从Critercism收到了来自现场用户的报告。 错误是“

  • 如果我有一个JLabel,我如何在10秒后移除它?我希望在删除JLabel后能够查看它。我想这可能与。