[英]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.