【问题标题】:C# Memory leak in Bitmap位图中的 C# 内存泄漏
【发布时间】:2013-02-19 12:48:05
【问题描述】:

我的应用程序在这行中出现内存泄漏。如果我查看任务管理器,每次触发此进程时,RAM 内存都会增加 +- 300 MB。

Bitmap bmp1 = new Bitmap(2480, 3508);
panel1.DrawToBitmap(bmp1, new Rectangle(0, 0, 2480, 3508));
pictureBox2.Image = bmp1;

有人可以帮我解决他的泄漏吗?如果我使用:

bmp1.Dispose();

我在“Program.cs”的这一行得到一个异常:Application.Run(new Form1()); 在此之后,应用程序停止运行......

屏幕应用:

【问题讨论】:

  • 例外是? ObjectDisposedExeption?
  • Offtopic 但请避免查看任务管理器并改为查看性能监视器
  • 您需要在完成后处理图像。当您不再显示图像时,您的应用程序是否存在问题?如果是这样,那就是你需要处理它的地方。
  • 我认为他在重复这个过程,而旧图像没有被清理(至少不是马上)。
  • 图片始终在picturebox1的屏幕中

标签: c# image bitmap


【解决方案1】:

更新:本身您没有内存泄漏,您只需要等待垃圾收集器释放资源即可。

如果你确实想要创建垃圾收集器collect,你可以这样做:

System.GC.Collect();
System.GC.WaitForPendingFinalizers();

为什么需要处理位图?如果您的 PictureBox 正在使用它,那么您需要位图。如果您要对其进行大量更改,也许您应该将旧位图换成新位图并丢弃旧位图:

Bitmap bmp1 = new Bitmap(2480, 3508);
panel1.DrawToBitmap(bmp1, new Rectangle(0, 0, 2480, 3508));
Image img = pictureBox1.Image;
pictureBox1.Image = bmp1;
if (img != null) img.Dispose(); // this may be null on the first iteration

【讨论】:

  • 这与调用Dispose 相同,显然会导致异常。
  • 我仍然得到相同的结果: bmp1.Dispose();并且应用程序已停止。
  • 不是和直接调用bmp1.Dispose();一样吗?
  • 可以,但最好使用using
  • 显然是Bitmap and Image never close the underlying stream. You'll have an eternal lock on that file, until the GC cares about collecting the floating reference。所以你仍然依赖 GC。
【解决方案2】:

我假设您应该只处理您不再需要的图像。您仍然需要创建 bmp1,只需将其设置为 pictureBox2.Image 字段的内容。尝试以下方式:

Bitmap bmp1 = new Bitmap(2480, 3508);
panel1.DrawToBitmap(bmp1, new Rectangle(0, 0, 2480, 3508));
Bitmap bmp2 = (Bitmap)pictureBox2.Image;
pictureBox2.Image = bmp1;
bmp2.Dispose();

免责声明:我对 C# 没有经验,所以我可能错了...

【讨论】:

  • 嗯,在这一行:Bitmap bmp2 = pictureBox2.Image;它说:“错误 1 ​​无法将类型 'System.Drawing.Image' 隐式转换为 'System.Drawing.Bitmap'。存在显式转换(您是否缺少演员表?)”
  • 没有意义,实际上你需要 Bitmap 活着,只要图片框显示它
  • @V4Vendetta 再次查看代码:这就是我的本意。它只处理不再显示的图像...我没有 C#,但由于我的答案与 Adam K Dean 接受的答案基本相同,我认为它确实有道理。
  • @Ferry 我用显式强制转换更新了代码,但稍微用谷歌搜索一下就可以解决问题 - 该错误消息并不少见......
【解决方案3】:

您应该使用外部 gdi32.dll 来避免位图内存泄漏

[System.Runtime.InteropServices.DllImport("gdi32.dll")] 
public static extern bool DeleteObject(IntPtr hObject);
//your bitmap usage code here
...
//delete bitmap handle when you don't need the bitmap anymore
DeleteObject((IntPtr)hBitmap);

【讨论】:

    【解决方案4】:
        Bitmap copy_Screen()
        {
            try
            {
                var bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
                var gfxScreenshot = Graphics.FromImage(bmpScreenshot);
                try
                {
                    gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy);
                }
                catch (Exception) { }
                return bmpScreenshot;
            }
            catch (Exception) { }
            return new Bitmap(10, 10, PixelFormat.Format32bppArgb);
        }
    
        private void button5_Click(object sender, EventArgs e)
        {
            //Start Stop timer
            if (timer1.Enabled == false) { timer1.Enabled = true; } else { timer1.Enabled = false; }
        }
    
        private void timer1_Tick(object sender, EventArgs e)
        {
            //memory leak solve
            System.GC.Collect();
            System.GC.WaitForPendingFinalizers();
    
            Bitmap BM = copy_Screen();
            if (pictureBox1.Image != null)
            {
                pictureBox1.Image.Dispose();
            }
            pictureBox1.Image = BM;
    
        }
    

    【讨论】:

    • 您为什么发布此代码?它解决了什么问题?
    猜你喜欢
    • 2013-10-01
    • 1970-01-01
    • 2016-03-14
    • 2011-10-22
    • 1970-01-01
    • 2013-06-05
    • 1970-01-01
    • 2012-05-15
    相关资源
    最近更新 更多