簡體   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