You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何不使用按钮调用Load_form函数,实现图片框自动更新并解决内存溢出问题

解决方案

异常原因

你遇到的Out of memory和Parameter is not valid异常本质是GDI资源泄漏:

  • Image、Bitmap、Graphics这类对象都属于非托管GDI资源,不会被GC自动回收,必须手动调用Dispose()释放
  • 原有代码每次加载新图片时,旧的图片资源没有被释放,累积到系统GDI对象上限就会抛出异常
  • 你代码中已经写了FileSystemWatcher的回调但没有初始化启用,还是用定时器轮询,无意义的重复加载进一步加速了资源消耗

修复步骤

1. 修复资源泄漏

修改setPaths方法,每次加载新图片前先释放所有旧资源,同时及时释放临时创建的原始图片、Bitmap对象,另外用FileStream加载避免锁死源图片文件:

public void setPaths(string[] paths, double defZoom)
{
    // 先释放所有旧的GDI资源
    if (pictureBox1.Image != null) { pictureBox1.Image.Dispose(); pictureBox1.Image = null; }
    if (pictureBox2.Image != null) { pictureBox2.Image.Dispose(); pictureBox2.Image = null; }
    if (pictureBox3.Image != null) { pictureBox3.Image.Dispose(); pictureBox3.Image = null; }
    if (actImage != null) { actImage.Dispose(); actImage = null; }
    if (actImage1 != null) { actImage1.Dispose(); actImage1 = null; }
    if (actImage2 != null) { actImage2.Dispose(); actImage2 = null; }

    viewerPaths = paths;
    pathsNumber = viewerPaths.Length;
    imageDefaultZoom = defZoom;
    int total = viewerPaths.Length;
    // 先判断文件数量足够再加载,避免索引越界
    if (pathsNumber >= 3) 
    {
        using (var fs = new FileStream(viewerPaths[total - 3], FileMode.Open, FileAccess.Read))
        using (actImage = Image.FromStream(fs))
        using (var b = new Bitmap(actImage))
        {
            var i = resizeImage(b, new Size(100, 100));
            pictureBox1.Image = i;
        }

        using (var fs = new FileStream(viewerPaths[total - 2], FileMode.Open, FileAccess.Read))
        using (actImage1 = Image.FromStream(fs))
        using (var b1 = new Bitmap(actImage1))
        {
            var i1 = resizeImage(b1, new Size(100, 100));
            pictureBox2.Image = i1;
        }

        using (var fs = new FileStream(viewerPaths[total - 1], FileMode.Open, FileAccess.Read))
        using (actImage2 = Image.FromStream(fs))
        using (var b2 = new Bitmap(actImage2))
        {
            var i2 = resizeImage(b2, new Size(100, 100));
            pictureBox3.Image = i2;
        }
    }
}

2. 启用FileSystemWatcher代替定时器轮询

用系统级的文件监听器实现新增文件实时感知,比定时器轮询效率更高,注意处理跨线程更新UI的问题:

// 全局声明监听器对象
private FileSystemWatcher _watcher;
private void Form1_Load(object sender, EventArgs e)
{
    imPaths = getFiles(pathLogNames, actCode, ".tif");
    setPaths(imPaths, 0.5);

    // 初始化文件监听器
    _watcher = new FileSystemWatcher(pathLogNames);
    _watcher.Filter = "*.tif";
    // 和你原getFiles的递归扫描逻辑对应,不需要扫子目录就设为false
    _watcher.IncludeSubdirectories = true; 
    _watcher.Created += OnChanged;
    _watcher.EnableRaisingEvents = true;
}

private void OnChanged(object sender, FileSystemEventArgs e)
{
    // FileSystemWatcher的回调在工作线程,必须回到UI线程操作控件
    if (this.InvokeRequired)
    {
        this.Invoke(new Action(() => OnChanged(sender, e)));
        return;
    }
    // 加100ms延时,避免文件还在写入时读取报错
    System.Threading.Thread.Sleep(100);
    imPaths = getFiles(pathLogNames, actCode, ".tif");
    // 判断文件列表真的有变化再更新,减少不必要的资源消耗
    if (!imPaths.SequenceEqual(viewerPaths))
    {
        setPaths(imPaths, 0.5);
    }
}

3. 窗体关闭时清理剩余资源

添加窗体关闭事件处理,彻底释放所有资源:

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
    _watcher?.Dispose();
    if (pictureBox1.Image != null) pictureBox1.Image.Dispose();
    if (pictureBox2.Image != null) pictureBox2.Image.Dispose();
    if (pictureBox3.Image != null) pictureBox3.Image.Dispose();
}

内容的提问来源于stack exchange,提问作者Oguz Kahraman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 08:15:01