IntPtr - 内存和 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();
我试图通过以下方式释放和删除创建的 objects,但没有任何效果。
g1.ReleaseHdc(dc3);
//Release the screen handle
g2.ReleaseHdc(dc2);
//Release the bitmap handle
DeleteObject(dc1);
DeleteObject(dc2);
DeleteObject(dc3);
我找到了使用 GarbageCollector 的解决方案。这样可行!不再有内存或 GDI 泄漏。我只是打电话
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
在我调用“GetSS”之后。
但我想了解为什么手动释放和删除 objects 不起作用,我想尽可能避免使用 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 解决了问题,则可能是由于某些终结器启动并释放了内存。这暗示它可能是一些没有被处理的一次性物品。 Graphics class 是 IDisposable,因此它们应该在 using 语句中以确保处置。位图似乎在函数外正确处理。
建议CreateDC
对应的函数是DeleteDC
.
我可能还建议释放 finally-statements 中的所有资源,以确保即使发生某些异常也能释放它们。
您缺少 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;
}
请不要忘记您 return 的图像也必须在某个时候处理掉。
问题: 在截取屏幕截图(循环)时,出现 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();
我试图通过以下方式释放和删除创建的 objects,但没有任何效果。
g1.ReleaseHdc(dc3);
//Release the screen handle
g2.ReleaseHdc(dc2);
//Release the bitmap handle
DeleteObject(dc1);
DeleteObject(dc2);
DeleteObject(dc3);
我找到了使用 GarbageCollector 的解决方案。这样可行!不再有内存或 GDI 泄漏。我只是打电话
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
在我调用“GetSS”之后。 但我想了解为什么手动释放和删除 objects 不起作用,我想尽可能避免使用 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 解决了问题,则可能是由于某些终结器启动并释放了内存。这暗示它可能是一些没有被处理的一次性物品。 Graphics class 是 IDisposable,因此它们应该在 using 语句中以确保处置。位图似乎在函数外正确处理。
CreateDC
对应的函数是DeleteDC
.
我可能还建议释放 finally-statements 中的所有资源,以确保即使发生某些异常也能释放它们。
您缺少 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;
}
请不要忘记您 return 的图像也必须在某个时候处理掉。