我的 hdc/hbitmap 的内存泄漏在哪里?
Where is the memory leak from my hdc/hbitmap?
所以我注意到我的部分代码在调用时泄漏了大量内存,我试图找出它泄漏的位置或原因,但我陷入了死胡同。
我已经尝试使用 Visual Studio 2017 调试器拍摄快照以找出泄漏发生的位置,但据此没有任何重大泄漏。我也试过 Deleaker,我有一次开始工作,它告诉我我泄露了 HDC 和 HBITMAP,但无法告诉我有多少内存。
第一个函数是 GetScreenBmp,这里可能会泄漏,但我没有正确释放所有内容吗?我知道我不会删除 hBitmap,但我需要 return。那是内存泄漏的地方吗?
HBITMAP GetScreenBmp(HDC hdc, int screenPositionX, int screenPositionY, int screenSizeX, int screenSizeY) {
// Get screen dimensions
int nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
int nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
int nMousePositionX = 0, nMousePositionY = 0;
// Create compatible DC, create a compatible bitmap and copy the screen using BitBlt()
HDC hCaptureDC = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, screenSizeX, screenSizeY);
HGDIOBJ hOld = SelectObject(hCaptureDC, hBitmap);
BOOL bOK = BitBlt(hCaptureDC, 0, 0, screenSizeX, screenSizeY, hdc, screenPositionX, screenPositionY, SRCCOPY | CAPTUREBLT);
SelectObject(hCaptureDC, hOld); // always select the previously selected object once done
DeleteObject(hOld);
DeleteDC(hCaptureDC);
return hBitmap;
第二部分是这段代码,我不确定我是否正确删除了所有内容。
HDC hdc = GetDC(0);
HBITMAP hBitmap = GetScreenBmp(hdc, currentSplitInformationArray.screenPositionX, currentSplitInformationArray.screenPositionY, currentSplitInformationArray.screenSizeX, currentSplitInformationArray.screenSizeY);
BITMAPINFO MyBMInfo = { 0 };
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
// Get the BITMAPINFO structure from the bitmap
if (0 == GetDIBits(hdc, hBitmap, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS)) {
MessageBox(NULL, "Resource not available\nDo you want to try again?", "Account Details", MB_ICONWARNING | MB_CANCELTRYCONTINUE | MB_DEFBUTTON2);
}
// create the bitmap buffer
BYTE* lpPixels = new BYTE[MyBMInfo.bmiHeader.biSizeImage];
// Better do this here - the original bitmap might have BI_BITFILEDS, which makes it
// necessary to read the color table - you might not want this.
MyBMInfo.bmiHeader.biCompression = BI_RGB;
MyBMInfo.bmiHeader.biHeight = currentSplitInformationArray.screenSizeY * -1;
// get the actual bitmap buffer
if (0 == GetDIBits(hdc, hBitmap, 0, currentSplitInformationArray.screenSizeY, (LPVOID)lpPixels, &MyBMInfo, DIB_RGB_COLORS)) {
MessageBox(NULL, "Resource not available\nDo you want to try again?", "Account Details", MB_ICONWARNING | MB_CANCELTRYCONTINUE | MB_DEFBUTTON2);
}
::SendMessage(testingComparison, STM_SETIMAGE,
(WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap);
DeleteObject(&MyBMInfo);
DeleteObject(hBitmap);
ReleaseDC(NULL, hdc);
delete[] lpPixels;
如果这是之前已经回答过的问题,或者如果答案很容易搜索到,我提前道歉,但我已经尝试了几个小时来修复它。
使用工具来跟踪您的 leaks/allocations(顺便说一句。您并没有 post 一开始是如何发现泄漏的)。
由于您使用的是 visual studio c++,因此您可以使用内置工具。基本上这 3 行的组合就可以完成工作。
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );//to enable, safe to always set somewhere around program startup - on normal exit this will print whatever you leaked
//_CrtDumpMemoryLeaks();//Dumps to see what has already been allocated
//_CrtSetBreakAlloc(#number);//Use this to set breakpoint using the allocation number from heap dump to see where allocation takes place. If allocation happends before this line it will not work.
好的,我找到了解决方案。 STM_SETIMAGE 消息 returns 之前的图片,你必须自己处理。 https://docs.microsoft.com/en-us/windows/desktop/Controls/stm-setimage
下次我应该学会更好地阅读文档,很抱歉浪费大家的时间。
::SendMessage(testingComparison, STM_SETIMAGE,
(WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap);
通过简单的操作修复了它
HBITMAP oldBitmap = (HBITMAP)::SendMessage(testingComparison, STM_SETIMAGE,
(WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap);
DeleteObject(oldBitmap);
所以我注意到我的部分代码在调用时泄漏了大量内存,我试图找出它泄漏的位置或原因,但我陷入了死胡同。
我已经尝试使用 Visual Studio 2017 调试器拍摄快照以找出泄漏发生的位置,但据此没有任何重大泄漏。我也试过 Deleaker,我有一次开始工作,它告诉我我泄露了 HDC 和 HBITMAP,但无法告诉我有多少内存。
第一个函数是 GetScreenBmp,这里可能会泄漏,但我没有正确释放所有内容吗?我知道我不会删除 hBitmap,但我需要 return。那是内存泄漏的地方吗?
HBITMAP GetScreenBmp(HDC hdc, int screenPositionX, int screenPositionY, int screenSizeX, int screenSizeY) {
// Get screen dimensions
int nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
int nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
int nMousePositionX = 0, nMousePositionY = 0;
// Create compatible DC, create a compatible bitmap and copy the screen using BitBlt()
HDC hCaptureDC = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, screenSizeX, screenSizeY);
HGDIOBJ hOld = SelectObject(hCaptureDC, hBitmap);
BOOL bOK = BitBlt(hCaptureDC, 0, 0, screenSizeX, screenSizeY, hdc, screenPositionX, screenPositionY, SRCCOPY | CAPTUREBLT);
SelectObject(hCaptureDC, hOld); // always select the previously selected object once done
DeleteObject(hOld);
DeleteDC(hCaptureDC);
return hBitmap;
第二部分是这段代码,我不确定我是否正确删除了所有内容。
HDC hdc = GetDC(0);
HBITMAP hBitmap = GetScreenBmp(hdc, currentSplitInformationArray.screenPositionX, currentSplitInformationArray.screenPositionY, currentSplitInformationArray.screenSizeX, currentSplitInformationArray.screenSizeY);
BITMAPINFO MyBMInfo = { 0 };
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
// Get the BITMAPINFO structure from the bitmap
if (0 == GetDIBits(hdc, hBitmap, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS)) {
MessageBox(NULL, "Resource not available\nDo you want to try again?", "Account Details", MB_ICONWARNING | MB_CANCELTRYCONTINUE | MB_DEFBUTTON2);
}
// create the bitmap buffer
BYTE* lpPixels = new BYTE[MyBMInfo.bmiHeader.biSizeImage];
// Better do this here - the original bitmap might have BI_BITFILEDS, which makes it
// necessary to read the color table - you might not want this.
MyBMInfo.bmiHeader.biCompression = BI_RGB;
MyBMInfo.bmiHeader.biHeight = currentSplitInformationArray.screenSizeY * -1;
// get the actual bitmap buffer
if (0 == GetDIBits(hdc, hBitmap, 0, currentSplitInformationArray.screenSizeY, (LPVOID)lpPixels, &MyBMInfo, DIB_RGB_COLORS)) {
MessageBox(NULL, "Resource not available\nDo you want to try again?", "Account Details", MB_ICONWARNING | MB_CANCELTRYCONTINUE | MB_DEFBUTTON2);
}
::SendMessage(testingComparison, STM_SETIMAGE,
(WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap);
DeleteObject(&MyBMInfo);
DeleteObject(hBitmap);
ReleaseDC(NULL, hdc);
delete[] lpPixels;
如果这是之前已经回答过的问题,或者如果答案很容易搜索到,我提前道歉,但我已经尝试了几个小时来修复它。
使用工具来跟踪您的 leaks/allocations(顺便说一句。您并没有 post 一开始是如何发现泄漏的)。
由于您使用的是 visual studio c++,因此您可以使用内置工具。基本上这 3 行的组合就可以完成工作。
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );//to enable, safe to always set somewhere around program startup - on normal exit this will print whatever you leaked
//_CrtDumpMemoryLeaks();//Dumps to see what has already been allocated
//_CrtSetBreakAlloc(#number);//Use this to set breakpoint using the allocation number from heap dump to see where allocation takes place. If allocation happends before this line it will not work.
好的,我找到了解决方案。 STM_SETIMAGE 消息 returns 之前的图片,你必须自己处理。 https://docs.microsoft.com/en-us/windows/desktop/Controls/stm-setimage
下次我应该学会更好地阅读文档,很抱歉浪费大家的时间。
::SendMessage(testingComparison, STM_SETIMAGE,
(WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap);
通过简单的操作修复了它
HBITMAP oldBitmap = (HBITMAP)::SendMessage(testingComparison, STM_SETIMAGE,
(WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap);
DeleteObject(oldBitmap);