【问题标题】:Show a lot of images with really low memory using in C#?在 C# 中使用非常低的内存显示大量图像?
【发布时间】:2013-05-05 22:16:02
【问题描述】:

我有一个表单,我在 Panel 中动态创建 8 个 PictureBoxes,其中显示 8 个不同的图像,每个 PictureBox 一个。图片为 50Kb Jpeg。 问题是我想让用户也看到 300 张图片,这就像 38 个面板,但每次我 LOAD 图像到 PictureBoxes 我的程序使用 5-7Mb 的 Ram 内存 更多。(我从 Windows 的任务管理器中看到) 我怎样才能减少这个增量?我的图片不是那么大,我只想显示预览,我不在乎质量。 这是我如何创建PictureBoxes:

private void buttonAdd_Click(object sender, EventArgs e)
{     
  Panel pan = new Panel();
  PictureBox pic1 = new PictureBox();
  pic1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
  pic1.Location = new System.Drawing.Point(208, 5);
  pic1.Name = "panel" + ctr.Count().ToString() + "pictureBox1";
  pic1.Size = new System.Drawing.Size(100, 100);
  pic1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
  ///
  /// Same thing other 7 times with differents name and location
  ///      
  pan.Location = new System.Drawing.Point(12, 55);
  pan.Name = "panel" + ctr.Count().ToString();
  pan.Size = new System.Drawing.Size(1088, 129);
  pan.TabIndex = 0;
  pan.AllowDrop = true;
  pan.BackColor = System.Drawing.SystemColors.ControlLight;
  pan.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;           
  pan.Controls.Add(pic1);
  ///
  /// Same thing other 7 times 
  ///        
  this.Controls.Add(pan);
  }

这是我如何填充它们的:

void buttonClickEvent(object sender, EventArgs e)
    {
        string[] files= Directory.GetFiles("mylocalpath");
        foreach(string x in files)
        {
            string imgIndex= x.Remove(0,x.LastIndexOf("_")+1).Remove(1);
            PictureBox pic=pictureBox1; 
            //I get it everytime from imgIndex and sender's parent,
            //too much code to show now
            pic.ImageLocation = x;
        }

    }

【问题讨论】:

  • 首先,不要相信任务管理器!
  • 尝试覆盖OnPaintOnRefresh,这样您就可以加载图像,绘制它,然后忘记它。仅适用于静态未隐藏图像。

标签: c# image memory picturebox


【解决方案1】:

您可以在很长一段时间内忽略 .NET 中的 IDisposable 接口。许多 .NET 程序员从不对一次性对象调用 Dispose() 方法,也从不使用 using 语句,他们的程序运行良好。垃圾收集器保持程序运行,调用此类类的终结器进行清理。

但是 Image 和 Bitmap 类是特殊的。它们是围绕 GDI+(一个非托管 API)的非常薄的托管类包装器。图像可以使用 很多 非托管内存来存储像素数据,大图像上可以使用许多兆字节。将它与一个不会分配足够的托管对象来触发垃圾收集的程序结合起来,你就会遇到一个胖猪问题。

必须在使用完图像后对其进行处置以避免此问题。当您使用 PictureBox.ImageLocation 属性时,这有点困难,PictureBox 类使用工作线程加载图像。它本身不能处理之前的图像,它不知道该图像是否可以在其他地方使用。你必须帮忙:

    foreach(string x in files)
    {
        string imgIndex = x.Remove(0,x.LastIndexOf("_")+1).Remove(1);
        PictureBox pic = pictureBox1; 
        //...
        if (pic.Image != null) pic.Image.Dispose();
        pic.Image = null;
        pic.ImageLocation = x;
    }

或者改用 Image.FromFile() 方法,这样你就不必看空的图片框了。

【讨论】:

  • 这可以很容易地与虚拟化结合。很高兴指出usingDispose
【解决方案2】:

显示图片由操作系统(GDI 子系统)处理,这会导致内存效率低下:图像在内部被渲染为原始大小的位图,使用大量内存,然后缩放此位图向下仅用于显示。

最好的办法是创建小型预览图像并改为显示这些图像。

另外请记住,您在垃圾收集环境中工作:并非您在任务管理器中看到的所有内存都真正被使用,如果内存压力增加,GC 会更积极地将内存返回给系统 - 实际上您的如果在可用内存较少的系统上运行,应用程序可能会使用较少的内存。

【讨论】:

  • 这些是非常有趣的信息,我不知道它是由操作系统处理的......但我已经尝试创建和加载小拇指,但没有任何改变。我知道taskmanager有时是个大骗子,所以我去看看,谢谢!
【解决方案3】:

也许 UI 虚拟化可以帮助您。

您想一次显示所有这些图片框吗?

据我了解您的问题,您只想一次显示其中的 8 个。

请看下面的文章UI / Data virtualization

尤其是virtualizing panel

【讨论】:

  • 对不起,如果我没有解释清楚,我想同时显示很多图像,按 8 分组,但总是同时显示很多。像 80 个面板,这意味着 640 个图像。但是,我不知道 UI / 数据虚拟化是什么,所以我会研究它,现在谢谢 :D
  • 那么虚拟化面板是你的选择
猜你喜欢
  • 2015-07-06
  • 1970-01-01
  • 1970-01-01
  • 2012-12-16
  • 2021-11-22
  • 2023-03-05
  • 2011-08-24
  • 1970-01-01
  • 2013-08-21
相关资源
最近更新 更多