我创建了一个由查询返回的数据填充的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列;没有图像或特定数据类型
这条消息究竟意味着什么,我该如何避免呢? 您可以通过更改此光标窗口来提高性能吗?
答案 0 :(得分:15)
根据我的经验,这意味着查询结果对于游标窗口而言太大,并且它会请求更多内存。大多数情况下,此请求很受欢迎,但在低端设备上,它可能会抛出异常。
我不知道有问题的应用程序的细节,但您提到了ListView。 ListView不能同时显示3700行,而endless list可以帮助按需加载数据
我的建议是将查询分解为多个查询,这些查询返回较小的结果并在运行下一个查询之前关闭它们。在每个连续查询结合后结果。
答案 1 :(得分:5)
简短版本:
经过一些调查,看来此消息是正常运行的一部分,而不是引起关注的原因。它是在“警告”级别记录的,但是我认为这太过急了。
长版:
(明显标记为)“窗口式”光标,这意味着旧记录将在获得新记录时被丢弃。以最简单的形式,这样的“窗口”实现可能总共包含多达N行,并且可能需要提前读取。但是,在此实现中,窗口大小由总大小定义。相反,保留在内存中的行数取决于整个窗口中可容纳的行数,并且在运行时会有所不同(也许可以将其视为“缓冲”游标而不是“窗口式”游标)。
作为具有(soft-?)上限大小的缓冲实现,仅当缓冲区太满而无法容纳下一行时,才会丢弃最早的行。在这种情况下,将删除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的问题)是问题。
答案 2 :(得分: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。