【问题标题】:C# WPF BitmapSource Memory Leak?C# WPF BitmapSource 内存泄漏?
【发布时间】:2011-11-05 07:58:05
【问题描述】:

我正在开发一个 BlackJack 程序,该程序显示一张 BlackJack 牌桌、纸牌等。计划是它会以自动化策略依次玩数千手牌。

我有一个 PlayerSeat UserControl,它包含一个绑定到 ObservableCollection 的 ItemsControl。此 CardInHand 类包含一个名为 CardImage 的 BitmapSource。当创建实例时,它会使用以下代码从资源中加载卡片图像:

[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);

private BitmapSource GenerateCardImage() {
        Stream TempStream = this.GetType().Assembly.GetManifestResourceStream("BlackJack.Resources.CardImages.Card_" + m_Card.ShortTitle + ".gif");
        System.Drawing.Bitmap sourceBMP = new System.Drawing.Bitmap(TempStream);
        BitmapSource tempBitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
            sourceBMP.GetHbitmap(),
            IntPtr.Zero,
            System.Windows.Int32Rect.Empty,
            BitmapSizeOptions.FromWidthAndHeight(sourceBMP.Width, sourceBMP.Height)
        );
        TempStream.Dispose();
        DeleteObject(sourceBMP.GetHbitmap());
        return tempBitmapSource;
}

问题是,在我运行了大约 500 轮(大约 4000 手或大约 10000 张卡片)后,我最终遇到了 GDI+ 错误,并且应用程序占用了大约 400MB 的 RAM。这增长很快,并且与已玩过的手数有关。

DeleteObject() 是我在另一个站点上发现的,它说这是从位图中释放资源的最佳方式。它可能会产生很小的影响,但不是我想要的。我也试过 Dispose()。

另一个网站说它与 ItemsSource 绑定有关。我去掉了绑定,记忆还在增长。相反,我离开了绑定并删除了生成位图的代码。它玩了 40,000 轮,并没有大幅增长(在运行的 40 分钟内可能增加了 20MB)。

ObservableCollection 在每一轮之后都会被 Clear() 处理。我尝试将集合、CardInHand 和 BitmapSource 属性清空,但无济于事。

如何让这些图像显示在屏幕上,同时确保它们的对象在不再需要后被正确销毁?

感谢您的宝贵时间。

【问题讨论】:

    标签: c# wpf memory-leaks bitmapsource


    【解决方案1】:

    首先,您只有 52 张卡片。只需预先创建图像并在应用程序的生命周期内保留它们。毕竟这是一场黑杰克游戏;可以安全地假设每张卡都会在某个时候被用到。

    也就是说,从流创建BitmapSource 对象存在问题。当流被释放时,流所持有的byte[] 没有被释放。 See my own question here。我没有投票关闭作为副本的唯一原因是因为我认为您真的应该只创建一次卡片并完成它,而不是创建这些图像 10,000 多次。

    【讨论】:

    • 这是有道理的。如果我在应用程序启动时生成一个 BitmapSource,我应该能够正确引用它吗?它只会在 CardInHand 类中存储对原始 BitmapSource 的引用,而不是复制数据,对吧?
    • @Caesar:是的,只需在启动时创建它们并将它们存储在字典或其他东西中。使用枚举将卡片类型映射到图像或随意管理它们,只是不要在每次需要时都创建新的。
    • 这里是Flyweight Pattern 的经典示例。
    • 谢谢大家。这非常有效。我最终按照 Ed S. 所说的去做。再次感谢您!
    • 也许我在这里遗漏了一些东西,但似乎在问题中,BitmapSource 不是基于流创建的,而是基于从中检索的位图句柄Bitmap 对象。
    猜你喜欢
    • 1970-01-01
    • 2010-09-18
    • 1970-01-01
    • 1970-01-01
    • 2011-02-21
    • 1970-01-01
    • 2010-12-05
    相关资源
    最近更新 更多