Image.SelectActiveFrame内存问题

发布于 2024-12-06 14:02:27 字数 1451 浏览 0 评论 0原文

我正在编写一个控件来显示图像。
我的问题是在多页 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,但是速度不好。
谢谢大家

I'm writing a control to show images.
My problem comes out using Image class on multipage TIFFs.
I use this (I post only relevant code) at the beginning:

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

then, when the user wants to show a different 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;
    }
}

Using img.SelectActiveFrame(FrameDimension.Page, page - 1); (in both versions) about 7MB are allocated in memory and those are never freed (even exiting the method)!!!
If I goes to next page 7MB are allocated and not freed everytime, while going back (on an already visited pages) previously allocated memory is used.
To give you an example: think Task Manager reports my app is using x MB; going one page forward memory increases to x + y (after SelectActiveFrame()) + z (Image ret = ...). Well, I should have x + z (y part should be zero or GC collected exiting the method), but obviously that's not what happens, even calling GC.Collect manually.
Going back to a previously visited page, memory increases effectively only with z, as expected.
I find it terrible (think about a file with 80 pages...), but how can I force img object to free allocated memory? Am I doing something wrong?
I've already thought closing and reopening img, but speed is not good.
Thanks to everybody

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

一腔孤↑勇 2024-12-13 14:02:27

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

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

Don't use new Bitmap(img) because it will force the system to create new memory for a new Bitmap object using 32-bit color by default.

You can just use var bitmap = (Bitmap)img; to retrieve a Bitmap object for that page.

篱下浅笙歌 2024-12-13 14:02:27

如果我没记错的话,你不会在每个可能的点上破坏使用过的控件。
我认为您可能需要对此进行测试 - 但请确保您正在处理所有使用过的控件。

IE。 ImageControlUsed.Dispose();

If I'm not mistaken you're not destroying the used controls at every possible point.
I think you might need to test this - but make sure that you're disposing all the used controls.

ie. ImageControlUsed.Dispose();

╰ゝ天使的微笑 2024-12-13 14:02:27

我在尝试不同的解决方案后回答了我的问题,并接受了 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() 获取的内存量(无论如何,如果您返回到先前看到的页面,则该内存不会重复)。
因此,您最好每次都打开和关闭图像,如下所示:

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;
    }
}

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

I answer my question after trying different solutions and accept soluzion given by user965487 because at the end he was right (thanks to Hans Passant too).
If you have a class (call it QV) similar to this

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);
    }
}

then every time you call GetPage(...) your memory will grow not only for the size of returned image, but also for img.SelectActiveFrame(...) statement. I don't know why and how, but it happens. Releasing returned image and calling frees memory for image size, not for the amount taken from SelectActiveFrame() (anyway this memory is not duplicated if you return on a previously seend page).
So you'd better open and close the image everytime, like this:

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;
    }
}

Payload for opening and disposing image everytime user requests a new page is really nothing compared to dangerous memory allcation done with first solution.
I hope someone needs this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文