【问题标题】:Advice on solving OutOfMemoryExceptions for CF关于解决 CF 的 OutOfMemoryExceptions 的建议
【发布时间】:2010-01-08 14:56:24
【问题描述】:

我的 CF 应用程序有一个非常定制的 UI,使用大量图像作为 UI 元素。当这些位图保存在内存中时,用户界面感觉更加流畅。当它们按需加载时,UI很慢,我可以看到按钮一个一个出现,看起来很糟糕。 很长一段时间以来,这一切都很好,但最近我发现该应用程序几乎使用了它可以获得的所有内存,即 32MB iirc。然后我开始使用远程性能监视器,看看我是否能找到任何清除内存的问题。

事实证明,使用 RPM 获取有用的 GC 堆快照很难:在我可能收到内存不足异常之前关闭,请求快照会导致立即抛出本机异常。不过,我可以偶尔找到一个 GC 快照。我在这里保存了一个:http://files.zzattack.org/misc/ramis.gclog 和截图在这里:http://files.zzattack.org/images/ramisgcsnapshot.png 对我来说,它看起来并不那么麻烦,到目前为止,最大的对象是一个包含我的资源文件的字节数组(大约 3MB 的 PNG 图像)。总共使用了 3643304b(约 3.5MB)的内存。这些图像以大约 20 种不同的形式分布在 UI 元素上。我不知道单独的线程对内存使用有什么影响,但大约有 5-6 个线程同时运行,其中至少有 4 个在 95% 的时间处于阻塞状态。

在程序中,当我尝试下载 2MB 的 gzip 压缩文件时,我总是会收到 OutOfMemoryException。当我调用 GC.GetTotalMemory(false) 时,我发现我确实在尝试分配比当前可用更多的内存。调用 GC.Collect 并再次尝试也不能“解决”/推迟我的问题。

我想要一些关于如何解决我的问题的建议。我绝对想要内存中的位图,但也许我可以限制位图可用的插槽数量,只在内存中保留最常用的插槽并按需加载其他插槽。这可能是一个长镜头,但也许我可以请求操作系统为我保留更多内存?我确信该应用程序只能在具有足够可用 RAM 的设备上运行。任何帮助表示赞赏,在此先感谢。

【问题讨论】:

    标签: memory-management compact-framework garbage-collection out-of-memory


    【解决方案1】:

    如果您在多个表单上使用相同的图像,您应该考虑将这些位图作为静态变量保存在所有表单都可以访问的类中。

    public class AppBitmaps
    {
      public static Bitmap LogoBitmap = new Bitmap(...);
    
      public static Bitmap ButtonBitmap = new Bitmap(...);
    }
    
    public class Form1
    {
      public Form1()
      {
        this.Control1.Image = AppBitmaps.LogoBitmap;
      }
    }
    

    这样您只在内存中保留该图像的一个实例,这应该会减少整体内存使用量。

    【讨论】:

    • 感谢您的评论。在旧情况下,我多次调用 ResourceManager.GetObject() 来加载我的位图。因为我需要非常小的本地化和缩放选项(即有时不同的图像 WVGA/VGA 分辨率),所以一切都是通过静态辅助函数获得的。因此,像您在此辅助函数中提出的那样添加缓存机制非常容易,这导致在内存中保存了一些位图。现在就足够了,谢谢!
    【解决方案2】:

    “使用 RPM 获取有用的 GC 堆快照很难” 也许您可以尝试一些用于 .NET CF 的分析器,我听说过 EQATEC 分析器,如果它可以帮助您处理线程。

    我避免 OOM 错误的方法是不为 MDI(多文档界面)类型的应用程序设计,在内存中只有一个表单)并在使用后将所有对象设置为空(特别是“较重的”,例如XML 文档)。

    另外,这可能是相关的: OutOfMemoryException When Creating a Large Bitmap in CF.NET

    【讨论】:

    • 缓存表单而不是即时关闭/重新创建它们会在切换表单时实现更平滑的过渡。因此,我想使用大量缓存的表单来保留我的设计。我以前使用过 EQATEC 分析器,但我记得,它不会记录内存占用。他们产品描述的第一行将证实这一点:“EQATEC Profiler 是一个代码分析器,而不是内存分析器。”
    【解决方案3】:

    如果这是您的应用程序全速运行的快照,那么我建议:

    • 这是另一个正在运行的应用程序
    • 您的应用程序调用到非托管 内存泄漏
    • 操作系统(定制的 CE?)有一个 泄漏
    • 或者别的什么

    【讨论】:

    • 事实上,我的设备有很多可用的 RAM。我使用的是标准的 WM6 专业设备,只运行了基本进程,而且我的代码只有很少的 P/Invoke 函数,这些函数通常只调用一次。我认为这与 winmo 应用程序需要处理的 32MB 地址空间限制有关。
    • 我认为这个限制不适用于 WM6?我知道它肯定适用于 WM5。无论哪种方式,我都忘记了您还需要将 GC 堆的大小和各种 CLR 缓存添加到您的分数(您可以从分析器中获得)。然后是 .dll(未压缩)的大小,以获得您的最终分数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-10-31
    • 2020-01-20
    • 2011-08-26
    • 2021-05-04
    • 1970-01-01
    • 1970-01-01
    • 2013-07-13
    相关资源
    最近更新 更多