4

我的紧凑框架应用程序通过将所有项目渲染到一个大的位图表面来创建一个平滑滚动列表,然后将该位图复制到屏幕上的偏移位置,以便仅显示适当的项目。旧版本只渲染当时应该出现在屏幕上的项目,但是这种方法对于平滑的滚动界面来说太慢了。

最初创建大位图时,它偶尔会生成 OutOfMemoryException。如果用户对设备执行软重置并再次运行应用程序,则可以毫无问题地执行创建。

看起来这个位图不是在程序内存中生成的,因为应用程序使用的程序内存量与新平滑滚动方法之前使用的程序内存量大致相同。

有什么方法可以防止这种异常吗?有什么方法可以在抛出异常之前释放我需要的内存(无论它在哪里)?

4

4 回答 4

1

就在我发布后,我想到了一些你可以做的事情来解决新版本的问题。您遇到的问题是 CF 试图找到一块可用于巨大位图的连续内存块,这有时是个问题。

除了创建一个大位图之外,您还可以创建一组较小的位图,每个项目一个,并将每个项目渲染到它自己的小位图上。在显示期间,您只需复制所需的位图。CF 将比创建一个大的位图更容易创建一堆小位图,并且你不应该有任何内存问题,除非这是一大堆项目。

我应该避免像“没有解决办法”这样的表达。

还有一点很重要:确保在完成后对每个位图调用 Dispose()。

于 2008-11-18T03:25:41.967 回答
1

我建议回到只渲染部分数据的旧机制,因为完全渲染数据的大小显然是一个问题。为了帮助防止渲染问题,我可能会在当前视图的上方和下方预渲染几行,以便它们可以在有限的影响下“滚动”。

于 2008-11-18T15:16:13.967 回答
0

您的位图肯定在程序内存中创建的。位图需要多少内存取决于它有多大,而这个所需的大小是否会生成 OutOfMemoryException 取决于 PDA 有多少可用内存(这使得这是一个随机发生的错误)。

抱歉,但这通常是一种不可取的控件渲染技术(尤其是在 Compact Framework 上),除了增加 PDA 上的物理内存外,没有任何解决办法,这通常是不可能的(而且通常也无法解决问题) ,因为无论设备有多少可用,CF 进程都限制为 32MB)。

您最好的选择是回到旧版本并提高其渲染速度。CF 上还有一种简单的技术可用于使控件双缓冲以消除闪烁。

于 2008-11-18T03:20:05.160 回答
0

由于您似乎遇到了设备限制,限制了您可以创建的位图空间的总大小(这些显然是在视频 RAM 中而不是一般程序内存中创建的),一种替代方法是将此处使用的大位图对象替换为一块普通的 Windows 内存块,通过调用 BitBlt API 函数来访问它以进行读取和写入。

最初创建内存块很棘手,您可能想问另一个关于此的 SO 问题(GCHandle.Alloc 可用于创建“固定”对象,这意味着 .NET 不允许在其中移动它内存,这在这里很重要)。我知道该怎么做,但我不确定我做对了,我宁愿有专家的意见。

一旦您创建了大块,您将遍历您的项目,将每个项目渲染为一个您不断重复使用的小位图(使用您现有的 .NET 代码),然后将其 BitBlt 到您的内存块中的适当位置。

创建整个缓存后,您的渲染代码应该像以前一样工作,不同之处在于您不是从大位图复制到渲染表面,而是从缓存块中进行 BitBlt。BitBlt 的参数与 DrawImage 的参数基本相同(目标、源、坐标和大小等)。

由于您是以这种方式使用常规内存而不是专门的视频 RAM 创建缓存,因此我认为您不会遇到同样的问题。但是,我肯定会让块创建代码首先工作并测试以确保它每次都能创建足够大的块。

更新:实际上,理想的方法是拥有一组较小的内存块而不是一个大的内存块(就像我认为是位图方法的问题),但你已经有足够的事情要做了。我使用过处理 5MB 和 10MB 对象的 CF 应用程序,无论如何这不是一个大问题(尽管当该块被固定时它可能是一个更大的问题 - 我不知道)。顺便说一句,我一直对创建位图的 OOME 感到惊讶,因为我知道位图比可用内存小得多,你也是 - 现在我知道为什么了。抱歉,起初我认为这是一个简单的解决方案。

于 2008-11-18T15:12:16.953 回答