在C#中使用真正低内存显示大量图像?

时间:2013-05-11 09:22:00

标签: c# image memory picturebox

我有一个表单,我在PictureBox中动态创建了8个Panel es,其中我显示了8个不同的图像,每个PictureBox一个。图像是50Kb Jpeg。 问题是我想让用户同时看到300张图片,就像38张面板一样,但每当我 LOAD 图像进入PictureBox时,我的程序就会使用5-7Mb的Ram内存< strong> MORE 。(我在Windows的任务管理器中看到它) 我怎样才能减少这个增量?我的图片不是那么大,我只想展示预览,我不关心质量。 以下是我如何创建PictureBox es:

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

    }

3 个答案:

答案 0 :(得分:2)

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

但是Image和Bitmap类很特别。它们是围绕GDI +的非常瘦的托管类包装器,一个非托管api。图像可以使用 lot 的非托管内存来存储像素数据,在大图像上存储许多兆字节。将它与一个程序相结合,否则这个程序不会分配足够的托管对象来触发垃圾收集,而且你有一个胖胖的小猪问题。

完成后使用必须处理图像以避免此问题。使用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()方法,这样您就不必查看空白图片框了。

答案 1 :(得分:1)

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

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

我理解你的问题,你只想一次显示其中的8个。

请查看以下文章UI / Data virtualization

,尤其是virtualizing panel

答案 2 :(得分:1)

显示图片由OS(GDI子系统)处理,这引入了已知的内存效率低下:图像内部呈现为原始大小的位图,使用大量内存,然后缩放此位图仅用于展示。

您最好的选择是创建小型预览图像并显示它们。

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