1

我有一个表单,我在其中动态创建 8PictureBox个 es,Panel其中显示 8 个不同的图像,每个PictureBox. 图片为 50Kb Jpeg。问题是我想让用户也看到 300 张图片,就像 38 个面板一样,但是每次我将图像加载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;
        }

    }
4

3 回答 3

2

您可以在很长一段时间内忽略 .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() 方法,这样您就不必查看空图片框。

于 2013-05-11T10:14:01.353 回答
1

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

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

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

请查看以下文章UI / 数据虚拟化

尤其是虚拟化面板

于 2013-05-11T09:26:12.060 回答
1

显示图片由操作系统(GDI 子系统)处理,这引入了已知的内存效率低下:图像在内部被渲染为原始大小的位图,使用大量内存,然后此位图仅按比例缩小展示。

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

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

于 2013-05-11T09:32:40.317 回答