C#创建PictureBox时触发OutOfMemoryException问题求助
批量创建PictureBox加载PNG触发OutOfMemoryException问题
问题详情
- 文件夹内共55张PNG图片,单张最大78KB,其余多在30-50KB区间
- 循环创建PictureBox并添加到FlowLayoutPanel时,执行
PictureBox picture = new()抛出内存不足异常 - 已尝试切换x64平台、启用
gcallowverylargeobjects配置、手动调用GC.Collect(),均未解决 - 分批加载(如仅4张)无异常,图片数量越多,异常触发概率越高
- 使用场景:窗体加载时展示所有图片;用户添加GIF链接后,清空面板重新加载以避免重复
- 计算最大图片内存占用:32位深×293宽度×254高度=2381504字节(约2.27MB)
核心代码片段
if (file.FullName.EndsWith(FileFormats[0])) { PictureBox picture = new() { Name = "picture", Size = new(45, 45), Image = Image.FromFile(file.FullName), SizeMode = PictureBoxSizeMode.Zoom }; picture.Click += Pic_Click; flowLayoutPanel1.Controls.Add(picture); }
解决方案
1. 加载时缩小图片并释放文件句柄
Image.FromFile会锁定文件且加载原始尺寸图片,即便PictureBox只显示45×45,内存中仍保留原始大图。改用流加载并缩小到显示尺寸,大幅降低内存占用:
using (var fs = new FileStream(file.FullName, FileMode.Open, FileAccess.Read)) using (var originalImage = Image.FromStream(fs)) { // 缩小到PictureBox的显示尺寸 using (var resizedBitmap = new Bitmap(45, 45)) { using (var g = Graphics.FromImage(resizedBitmap)) { g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.DrawImage(originalImage, 0, 0, 45, 45); } // 转换为非索引格式Bitmap,避免后续内存泄漏 var displayImage = new Bitmap(resizedBitmap); var picture = new PictureBox { Name = "picture", Size = new Size(45, 45), Image = displayImage, SizeMode = PictureBoxSizeMode.Zoom }; picture.Click += Pic_Click; flowLayoutPanel1.Controls.Add(picture); } }
2. 清空面板时彻底释放资源
清空FlowLayoutPanel时,必须手动释放每个PictureBox的Image资源和控件本身,否则GC无法及时回收内存:
foreach (Control ctrl in flowLayoutPanel1.Controls.OfType<PictureBox>().ToList()) { ctrl.Click -= Pic_Click; // 移除事件绑定 ctrl.Image?.Dispose(); // 释放图片资源 ctrl.Dispose(); // 释放控件 } flowLayoutPanel1.Controls.Clear();
3. 缓存重复图片(可选)
如果存在重复的图片路径,缓存已缩小的图片,避免重复加载占用内存:
// 类级别缓存字典 private readonly Dictionary<string, Image> _imageCache = new(); // 加载图片逻辑 if (!_imageCache.TryGetValue(file.FullName, out var cachedImage)) { // 执行上面的缩小加载逻辑,将displayImage存入缓存 _imageCache[file.FullName] = displayImage; } else { // 使用缓存的图片创建PictureBox var picture = new PictureBox { Name = "picture", Size = new Size(45, 45), Image = cachedImage, SizeMode = PictureBoxSizeMode.Zoom }; picture.Click += Pic_Click; flowLayoutPanel1.Controls.Add(picture); }
内容的提问来源于stack exchange,提问作者Ahmed Sherif
相关产品推荐
相关产品推荐

