Image.SelectActiveFrame内存问题

时间:2011-09-26 16:27:43

标签: c# image memory-leaks

我正在写一个控件来显示图像 我的问题出现在多页TIFF上使用Image类 我在开头使用它(我只发布相关代码):

Image img;
int pages;
img = Bitmap.FromFile(filename);
pages = img.GetFrameCount(FrameDimension.Page);

然后,当用户想要显示不同的页面时:

public override Image GetPage(int page)
{
    if (page < 1 || page > pages) return null;
    try
    {
        #if !TEST
            img.SelectActiveFrame(FrameDimension.Page, page - 1);
            return new Bitmap(img);
        #else
            MemoryStream ms = new MemoryStream();
            img.SelectActiveFrame(FrameDimension.Page, page - 1);
            img.Save(ms, ImageFormat.Jpeg);
            Image ret = Image.FromStream(ms);
            ms.Flush();
            ms.Dispose();
            return ret;
        #endif
    }
    catch (Exception ex)
    {
        "Tiff GetPage error: {0}".ToDebug(ex.Message);
        return null;
    }
}

使用img.SelectActiveFrame(FrameDimension.Page, page - 1);(在两个版本中)大约7MB在内存中分配,并且永远不会释放(甚至退出方法)!!! 如果我转到下一页,则分配7MB并且不会每次都释放 ,而在返回时(在已访问过的页面上)使用先前分配的内存。
举个例子:想想任务管理器报告我的应用程序正在使用x MB;前进一页内存增加到x + y(SelectActiveFrame()之后)+ z(Image ret = ...)。好吧,我应该有x + z(y部分应该为零或GC收集退出方法),但显然不会发生什么,甚至手动调用GC.Collect
返回到之前访问过的页面,内存仅按照z有效增加,如预期的那样 我发现它很糟糕(考虑一个80页的文件...),但是我如何强制img对象释放分配的内存?我做错了吗? 我已经想过关闭并重新打开img,但速度并不好 感谢大家

3 个答案:

答案 0 :(得分:2)

不要使用新的Bitmap(img),因为它会强制系统默认使用32位颜色为新的Bitmap对象创建新的内存。

你可以使用var bitmap =(Bitmap)img;检索该页面的Bitmap对象。

答案 1 :(得分:0)

如果我没弄错的话,你并没有在任何可能的地方摧毁使用过的控件。 我想你可能需要测试一下 - 但要确保你处理所有使用过的控件。

即。 ImageControlUsed.Dispose();

答案 2 :(得分:0)

我在尝试不同的解决方案之后回答我的问题并接受user965487给出的解决方案,因为最后他是对的(感谢Hans Passant)。
如果你有一个类(称为QV)类似于这个

public class QV
{
    Image img;
    int pages;

    public QV(filename) {
       img = Bitmap.FromFile(filename);
       pages = img.GetFrameCount(FrameDimension.Page);
    }

    ~QV() {
        img.Dispose();
        img = null;
    }

    public Image GetPage(int page) {
        if (page < 1 || page > pages) return null;
        img.SelectActiveFrame(FrameDimension.Page, page - 1);
        return new Bitmap(img);
    }
}

然后每次调用GetPage(...)时,您的记忆力不仅会增加返回图像的大小,还会增加img.SelectActiveFrame(...)语句的大小。我不知道为什么以及如何,但它发生了。释放返回的图像并调用释放内存以获取图像大小,而不是从 SelectActiveFrame()获取的数量(无论如何,如果您在之前的seend页面上返回,则此内存不会重复)。
因此,您最好每次打开和关闭图像,如下所示:

public class QV
{
    Image img;
    int pages;

    public QV(filename) {
       img = Bitmap.FromFile(filename);
       pages = img.GetFrameCount(FrameDimension.Page);
       img.Dispose();
    }

    public Image GetPage(int page) {
        if (page < 1 || page > pages) return null;
        img = Bitmap.FromFile(filename);
        img.SelectActiveFrame(FrameDimension.Page, page - 1);
        Image ret = Bitmap(img);
        img.Dispose();
        return ret;
    }
}

每次用户请求新页面时打开和处理图像的有效负载与使用第一个解决方案完成的危险内存分配相比实际上没有任何意义。
我希望有人需要这个。