图像加载内存泄漏与 C# [英] Image loading memory leak with C#

查看:49
本文介绍了图像加载内存泄漏与 C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序中存在内存泄漏问题,它加载了大量图像.我对 C# 比较陌生,并且认为我的内存泄漏问题已经过去了.我想不通问题 - 也许我正在使用一些我没有正确处理的非托管模块?

I have a memory leak issue in my application which loads a large amount of images. I'm rather new to C#, and thought my days of memory leak issues were past. I can't figure out the problem - maybe I'm using some unmanaged modules which I'm not handle correctly?

为了说明我的问题,我简化了导致问题的核心,并将其转移到一个干净的项目中.请注意,这都是愚蠢的代码,并没有反映它来自的原始应用程序.在测试应用程序中,我有 2 个按钮,触发两个事件.

To illustrate my problem I've simplified the core of what causes the problem and moved this to a clean project. Note that this is all silly code which doesn't reflect the original application it came from. In the test application I have 2 buttons, triggering two events.

按钮 1 - 创建:将对象设置为数据上下文.这将加载图像并通过将对象设置为 DataContext 使它们保持活动状态:

Button 1 - Create: Setting an object to the datacontext. This will load the images and keep them alive by setting the object to the DataContext:

var imgPath = @"C:some_fixed_pathimg.jpg";
DataContext = new SillyImageLoader(imgPath);

按钮 2 - 清理:我的理解是,如果我放开持有再次持有图像的 SillyImageLoader 的引用,那么它将被删除.我还显式地触发垃圾回收只是为了在删除引用后立即查看内存量.

Button 2 - CleanUp: My understanding is that if I let go of the reference holding the SillyImageLoader which again holds the images, then this will be deleted. I also explicitly trigger garbage collection just to see immediately the amount of memory after dropping the reference.

DataContext = null; 
System.GC.Collect();

测试时我正在加载 974KB jpeg 图像.持有 30 个位图表示将我的应用程序的内存使用量从 ~18MB 提高到 ~562MB.行.但是当我点击清理时,内存只下降到 ~292MB.如果我重复 Create+CleanUp,我会剩下大约 250MB 的内存.所以显然有些东西仍然被某人持有.

When testing I'm loading a 974KB jpeg image. Holding 30 bitmap representations of this boosts the memory usage of my application from ~18MB to ~562MB. Ok. But when I hit cleanup the memory drops only to ~292MB. If I repeat Create+CleanUp I'm left with another ~250MB memory. So obviously something is still held by someone.

这是 SillyImageLoader 代码:

Here is the SillyImageLoader-code:

namespace MemoryLeakTest
{
    using System;
    using System.Drawing;
    using System.Windows;
    using System.Windows.Interop;
    using System.Windows.Media.Imaging;

    public class SillyImageLoader
    {
        private BitmapSource[] _images; 

        public SillyImageLoader(string path)
        {
            DummyLoad(path);
        }

        private void DummyLoad(string path)
        {
            const int numberOfCopies = 30;
            _images = new BitmapSource[numberOfCopies];

            for (int i = 0; i < numberOfCopies; i++)
            {
                _images[i] = LoadImage(path);
            }
        }

        private static BitmapSource LoadImage(string path)
        {
            using (var bmp = new Bitmap(path))
            {
                return Imaging.CreateBitmapSourceFromHBitmap(
                    bmp.GetHbitmap(),
                    IntPtr.Zero,
                    Int32Rect.Empty,
                    BitmapSizeOptions.FromEmptyOptions());
            }            
        }
    }
}

有什么想法吗?问题似乎出在 BitmapSource 上.只持有 Bitmap 没有内存泄漏.我正在使用 BitmapSource 将其设置为图像的 Source 属性.我应该以不同的方式这样做吗?如果是这样 - 我仍然想知道内存泄漏的答案.

Any ideas? The problem seems to be with the BitmapSource. Holding only the Bitmap there is no memory leak. I am using BitmapSource to be able to set this to the Source property of an Image. Should I do this differently? If so - I'd still like to know the answer the memory leak.

谢谢.

推荐答案

当你打电话

bmp.GetHbitmap()

创建了位图的副本.您需要保留对指向该对象的指针的引用并调用

a copy of the bitmap is created. You'll need to keep a reference to the pointer to that object and call

DeleteObject(...)

在它上面.

来自此处:

备注

您有责任致电GDI DeleteObject 方法来释放GDI位图对象使用的内存.

You are responsible for calling the GDI DeleteObject method to free the memory used by the GDI bitmap object.

<小时>

您可以使用 BitmapImage 而不是 BitmapSource.这允许您一步加载和创建.


You may be able to save yourself the headache (and overhead) of copying the bitmap by using BitmapImage instead of BitmapSource. This allows you to load and create in one step.

这篇关于图像加载内存泄漏与 C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆