在CF.NET中创建大位图时出现OutOfMemoryException

时间:2008-11-18 02:36:06

标签: compact-framework gdi+ bitmap

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

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

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

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

4 个答案:

答案 0 :(得分:1)

就在我发布之后,我想到了可以做的事情,以解决新版本的问题。你遇到的问题是CF尝试找到一个可用于大位图的连续内存块,而这偶尔会出现问题。

您可以改为创建一个较小位图的集合,而不是创建一个大位图,每个项目对应一个位图,并将每个项目渲染到自己的小位图上。在显示期间,您只需复制所需的位图。 CF会比创建一个大位图更容易创建一堆小位图,除非这是一堆真正庞大的项目,否则你不应该有任何内存问题。

我应该避免像“没有修复”这样的表达。

另一个重点:确保在完成每个位图时调用Dispose()。

答案 1 :(得分:1)

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

答案 2 :(得分:0)

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

很抱歉,这通常是一种不可取的控制渲染技术(特别是在Compact Framework上),对于这种技术来说,没有任何修复方法可以解决增加PDA上的物理内存的问题,这通常是不可能的(通常无法修复)无论如何,问题是因为无论设备有多少,CF进程都限制在32MB。

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

答案 3 :(得分:0)

因为看起来你遇到了限制你可以创建的位图空间总大小的设备限制(这些显然是在视频RAM而不是通用程序存储器中创建的),另一种方法是替换大的Bitmap对象这里使用了一个普通的Windows内存块,通过PInvoking BitBlt API函数访问它以进行读写。

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

一旦你创建了大块,你就会遍历你的项目,将每个项目呈现为一个你继续重复使用的小位图(使用你现有的.NET代码),并将它BitBlt到你的适当位置记忆块。

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

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

更新:实际上,理想的方法是拥有一个较小的内存块而不是一个大的内存块(就像我认为是Bitmap方法的问题),但你已经有足够的事情了。我曾经使用处理5和10MB对象的CF应用程序,但这不是一个大问题(尽管当这个块固定时它可能是一个更大的问题 - 我不知道)。顺便说一句,我总是对OMap在BitMap创建上感到惊讶,因为我知道位图比可用内存小得多,就像你一样 - 现在我知道为什么了。抱歉,我认为这起初很容易解决。