【问题标题】:Cursor window: window is full光标窗口:窗口已满
【发布时间】:2013-12-04 08:32:35
【问题描述】:

我创建了一个由查询返回的数据填充的 ListView。
它有效,但在 LogCat 中我收到了消息:

Cursor Window: Window is full: requested allocation 444 bytes, free space 363 bytes, window size 2097152 bytes

它使用几分钟来加载/可视化 ListView。

我的查询返回大约 3700 行 String/Int/Double,每行有 30 列;没有图像或特定数据类型

此消息的确切含义是什么,我该如何避免它?
您可以通过更改此光标窗口来提高性能吗?

【问题讨论】:

  • 谢谢,但我已经看到了这个问题,我不能使用 SD 卡
  • 这个有什么更新吗?在某些情况下,我在字符串列表中遇到了同样的问题。
  • 是的,我换工作了 :) 抱歉,没有更新
  • @RichardLeMesurier 你是怎么解决的?我也遇到了同样的问题

标签: android android-listview database-cursor


【解决方案1】:

根据我的经验,这意味着查询结果对于光标的窗口来说太大了,它需要更多的内存。大多数情况下,此请求会得到尊重,但在低端设备上它可能会引发异常。

我不知道相关应用的具体细节,但您提到了 ListView。 ListView 不能一次显示 3700 行,endless list 可以帮助按需加载数据

我的建议是将查询分解为多个查询,这些查询返回较小的结果并在运行下一个查询之前关闭它们。在每次连续查询之后合并结果。

【讨论】:

  • ListView 可以显示超过 10 000 行的游标(根据我自己的经验)。这个问题显然与内存有关,而不是行数。
  • @matreshkin 同意,这就是 ListView 的重点:根据屏幕上的可见内容延迟加载和呈现行。
  • 顺便说一句,现在我看到@Delblanco 写了“A ListView cannot show 3700 rows AT ONCE”。听起来令人困惑,但实际上附加到 Window 的 3700 个视图似乎是不寻常的情况:)
  • 这个答案具有误导性:为了找出这个日志消息是否表明存在真正的问题,您应该比较当前“请求分配”的值和总“窗口大小”的值。更多细节 - 在下面@user1575326 的回答中。
  • “ListView 不能一次显示 3700 行”- ListView 不会一次将所有视图加载到内存中。这就是 ScrollView 中的 ListViewLinearLayout 之间的区别。
【解决方案2】:

短版:

经过一些调查,此消息似乎是正常操作的一部分,无需担心。它被记录在“警告”级别,但我认为这只是过于急切。

加长版:

这是(明确标记为)“窗口化”游标,这意味着旧记录将在获得新记录时被丢弃。在最简单的形式中,这样的“窗口”实现可能总共包含多达 N 行,可能带有一些预读。然而,在这个实现中,窗口大小是由总大小来定义的。相反,保留在内存中的行数取决于整个窗口中可以容纳的行数,并且在运行时会有所不同(这可能被认为更像是“缓冲”游标而不是“窗口化”游标)。

作为具有(软?)大小上限的缓冲实现,只有当缓冲区太满而无法容纳下一行时,才会丢弃最早的行。在这种情况下,会删除 1 个或多个较旧的行。这种“根据需要继续分配行,直到我们不再有更多空间,此时我们释放缓冲区中最旧的记录并重试”过程似乎是完全正常和预期的,作为正常部分保持内存空间受限的进程。

我的这个结论是基于阅读这里的源代码,并结合一些推论: https://android.googlesource.com/platform/frameworks/base/+/master/libs/androidfw/CursorWindow.cpp

人们为什么要谈论图像和其他大型 LOB?

如果单行的大小大于整个“窗口”(缓冲区),那么这个策略就会失效,你就会遇到实际问题。

这是@op 收到的消息:

Cursor Window: Window is full: requested allocation 444 bytes, free space 363 bytes, window size 2097152 bytes

这是@vovahost 收到的消息:

CursorWindow: Window is full: requested allocation 2202504 bytes, free space 2076560 bytes, window size 2097152 bytes

在第一种情况下,请求的分配远小于窗口大小。我希望重复发出类似的消息,具有相同的窗口大小和不同的请求分配大小。每次打印时,都会从较大的窗口中释放内存,并进行新的分配。这是正常且健康的操作。

在第二种情况下,请求的分配大小超过了整体窗口大小。这是一个实际问题,需要以更可流化的方式存储和读取数据。

区别在于“长度”(总行数)与“宽度”(最大单行的内存成本)。前者(@tirrel 的问题)不是问题,但后者(@vovahost 的问题)是。

【讨论】:

  • 很好而彻底的答案。
【解决方案3】:

我也遇到了这个问题。就我而言,我在数据库中保存了一个 2.2 MB 的图像。使用 Cursor.getBlob() 从数据库加载数据时,我会在日志中看到这条消息:

CursorWindow: Window is full: requested allocation 2202504 bytes, free space 2076560 bytes, window size 2097152 bytes

如果我尝试检索连续行的任何数据(字符串、数字等),则会收到此消息后,它会返回为 null 而没有任何错误。 解决方案是删除 2.2 MB 的 blob。我不知道是否可以从 Android 的数据库中加载更大的 blob。

【讨论】:

    【解决方案4】:

    另外,请注意更改窗口会产生 IPC 开销。

    因此,如果光标有大量项目并且与列表视图一起使用,快速导航会导致窗口更改,从而导致频繁的 IPC。如果系统已加载,这可能会导致 ANR。

    【讨论】:

    • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-28
    • 2018-12-04
    • 2020-03-14
    • 2011-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多