繁体   English   中英

IntPtr - Memory & GDI 泄漏 [C#]

[英]IntPtr - Memory & GDI leak [C#]

问题:当截取屏幕截图时(在循环中),我发现 RAM 和 GDI 泄漏。

private Bitmap GetSS(int ScreenWidth, int ScreenHeight, int ScreenWidthCut, int ScreenHeightCut)
    {
        
        int ScreenLocWidth = Screen.PrimaryScreen.Bounds.Width - ScreenWidth;
        int ScreenLocHeight = Screen.PrimaryScreen.Bounds.Height - ScreenHeight;

        IntPtr dc1 = CreateDC("DISPLAY", null, null, (IntPtr)null);
        //Create the DC of the display
        Graphics g1 = Graphics.FromHdc(dc1);
        //Create a new Graphics object from the handle of a specified device
        Bitmap MyImage = new Bitmap(ScreenWidthCut, ScreenHeightCut, g1);
        //Create a Bitmap object of the same size according to the screen size
        Graphics g2 = Graphics.FromImage(MyImage);

        //Get the handle of the screen
        IntPtr dc3 = g1.GetHdc();
        //Get the handle of the bitmap
        IntPtr dc2 = g2.GetHdc();
        BitBlt(dc2, 0, 0, ScreenWidth, ScreenHeight, dc3, ScreenLocWidth, ScreenLocHeight,
            (int)CopyPixelOperation.SourceCopy | (int)CopyPixelOperation.CaptureBlt);
        g1.ReleaseHdc(dc3);
        //Release the screen handle
        g2.ReleaseHdc(dc2);
        //Release the bitmap handle
        DeleteObject(dc1);
        DeleteObject(dc2);
        DeleteObject(dc3);
        
        return MyImage;
    }

调试给了我这些可能导致泄漏的行。

//Get the handle of the screen
        IntPtr dc3 = g1.GetHdc();
        //Get the handle of the bitmap
        IntPtr dc2 = g2.GetHdc();

通过以下内容,我试图释放和删除创建的对象,但没有任何效果。

g1.ReleaseHdc(dc3);
    //Release the screen handle
    g2.ReleaseHdc(dc2);
    //Release the bitmap handle
    DeleteObject(dc1);
    DeleteObject(dc2);
    DeleteObject(dc3);

我找到了一个使用 GarbageCollector 的解决方案。 这样可行。 不再有 memory 或 GDI 泄漏。 我只是打电话

GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);

在我调用“GetSS”之后。 但我想了解为什么手动释放和删除对象不起作用,我想尽可能避免使用 GarbageCollector。

编辑:这就是我所说的 GetSS

while (startLoc.x == 0) 
        {
            using (Bitmap imgScene = GetSS(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, Screen.PrimaryScreen.Bounds.Width, (int)(Screen.PrimaryScreen.Bounds.Height * 0.20)))
            {
                //the stuff I do with the image is commented out for testing purposes, this is not causing th leak
            }
            Thread.Sleep(10);
            GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
        }

这是为了删除 Object:

[System.Runtime.InteropServices.DllImport("gdi32.dll")]
    public static extern bool DeleteObject(IntPtr hObject);

大家保持健康。

如果强制 GC 解决了问题,则可能是由于一些终结器启动并释放了 memory。这暗示它可能是一些一次性 object 没有被处理。 Graphics class 是 IDisposable,因此它们应该在 using 语句中以确保处置。 bitmap 似乎正确地放置在 function 之外。

表明CreateDC对应的 function 是DeleteDC

我可能还建议在 finally 语句中释放所有资源,以确保即使发生某些异常也能释放它们。

您缺少using块,而且DeleteObject应该是DeleteDC ,它也应该在finally中。

此外, dc3不是必需的,因为您已经在dc1中拥有它。

 private Bitmap GetSS(int ScreenWidth, int ScreenHeight, int ScreenWidthCut, int ScreenHeightCut)
 {
     int ScreenLocWidth = Screen.PrimaryScreen.Bounds.Width - ScreenWidth;
     int ScreenLocHeight = Screen.PrimaryScreen.Bounds.Height - ScreenHeight;

     Bitmap MyImage;
     IntPtr dc1 = IntPtr.Zero;
     IntPtr dc2 = IntPtr.Zero;
     try
     {
         dc1 = CreateDC("DISPLAY", null, null, (IntPtr)null);
         //Create the DC of the display
         //Create a Bitmap object of the same size according to the screen size
         using (Graphics g1 = Graphics.FromHdc(dc1))
         {
             MyImage = new Bitmap(ScreenWidthCut, ScreenHeightCut, g1);
             using (Graphics g2 = Graphics.FromImage(MyImage))
             {
                 //Get the handle of the bitmap
                 dc2 = g2.GetHdc();
                 BitBlt(dc2, 0, 0, ScreenWidth, ScreenHeight, dc1, ScreenLocWidth, ScreenLocHeight,
                     (int)CopyPixelOperation.SourceCopy | (int)CopyPixelOperation.CaptureBlt);
             }
         }
     }
     catch
     {
         MyImage?.Dispose();
         throw;
     }
     finally
     {
         //Release the bitmap handle
         if (dc1 != IntPtr.Zero)
             DeleteObject(dc1);
         if (dc2 != IntPtr.Zero)
             g2.ReleaseHdc(dc2);
     }
     
     return MyImage;
 }

不要忘记,您返回的图像也必须在某个时候处理掉。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM