【发布时间】:2019-06-22 01:03:44
【问题描述】:
我无法管理在屏幕截图对象类中创建的位图和 CLSID 对象的内存。这两个都来自 GDI+ 库。标头列出了 Screenshot.h 中的以下私有变量
#include <gdiplus.h>
#include <iostream>
#include <fstream>
#include <string>
#include "windows.h"
#pragma once
#pragma comment(lib, "gdiplus.lib")
using namespace std;
using namespace Gdiplus;
class Screenshot
{
private:
HDC dc, memdc, fontdc;
HBITMAP membit;
Bitmap* bmpPtr;
CLSID clsid;
ULONG_PTR gdiplusToken;
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid);
public:
Screenshot();
~Screenshot();
void TakeScreenshot(string userAction, string winName, long xMousePos, long yMousePos, long long tStamp);
void SaveScreenshot(string filename);
void memoryManagement();
};
然后当我的主程序截屏时,值是用 TakeScreenshot() 填充的,但还没有保存到磁盘
void Screenshot::TakeScreenshot(//redacted for readibility) {
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
HWND hwnd = GetDesktopWindow();
dc = ::GetDC(0);
int scaleHeight, scaleWidth = 0;
int Height = GetSystemMetrics(SM_CYVIRTUALSCREEN);
int Width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
scaleHeight = Height + (0.1 * Height);
memdc = CreateCompatibleDC(dc);
membit = CreateCompatibleBitmap(dc, Width, scaleHeight);
HBITMAP bmpContainer = (HBITMAP)SelectObject(memdc, membit);
BitBlt(memdc, 0, 0, Width, Height, dc, 0, 0, SRCCOPY);
//Other code that adds fonts, etc. Does not invoke bmpPtr
bmpPtr = new Bitmap(membit, NULL);
GetEncoderClsid(L"image/jpeg", &clsid);
如果屏幕截图被保存,另一个函数 SaveScreenshot() 使用 bmpPtr->Save() 并在其中调用 Gdiplus 关闭。但是,某些屏幕截图会从队列(STL 队列)中弹出并超出内存而不是保存,如下所示:
void ManageQueue(Screenshot& ssObj)
{
//If queue contains 30 screenshots, pop off first element and push new object
//Else just push new object
if (screenshotQueue.size() == MAX_SCREENSHOTS)
{
screenshotQueue.front().memoryManagement();
screenshotQueue.pop();
screenshotQueue.push(ssObj);
}
else
{
screenshotQueue.push(ssObj);
}
}
我编写了一个 MemoryManagement() 函数来在屏幕截图弹出之前执行必要的释放和删除。如果屏幕截图已保存,则不会调用此函数:
void Screenshot::memoryManagement()
{
delete bmpPtr;
delete &clsid;
ReleaseDC(NULL, memdc);
DeleteObject(fontdc);
DeleteObject(memdc);
DeleteObject(membit);
}
当调用 bmpPtr 或 clsid 上的 delete 时,无论是来自该函数还是在解构器中,程序都会崩溃。我现在在程序中遇到了严重的内存泄漏,并且没有运行相当于 Valgrind 的 Windows,我假设它来自这里。如何成功删除这些对象?作为贡献的程序员,我会将源代码中的任何答案归功于我。如果需要,请留下任何改进我的问题的建议。
【问题讨论】:
-
在
delete中使用地址运算符&是一个很大的危险信号。只有delete你实际上是new(和delete[]你是new[])。 -
我也许可以不删除 clsid 就逃脱,但位图肯定需要删除。完全删除 delete &clsid 仍然会导致 delete bmpPtr 崩溃。
-
也许你应该显示
Bitmap的构造函数和析构函数。将日志记录添加到您的程序或在调试器中逐步执行它,以确保被删除的bmpPtr的指针值与您分配的指针值相同。问题也可能在其他地方,这取决于这些是否是Screenshot类中的成员变量(您对此不清楚),以及Screenshot类是如何构造、破坏、复制或通常以其他方式使用的。 -
好吧,
bmpPtr = new Bitmap(membit, NULL);你当然应该这样做delete bmpPtr。如果崩溃,那么问题很可能出现在Bitmap类中(您没有向我们展示),但也可能是因为您对bmpPtr进行了一些重新分配而您没有向我们展示,或者因为您delete bmpPtr多次? -
澄清:位图、HDC等是Gdi+库的一部分,不是我写的类或
Screenshot的一部分。根据 MSDN,使用Bitmap构造函数分配的新位图会保留在内存中,“直到 Bitmap::Bitmap 对象被删除或超出范围”。 bmpPtr 仅在我上面显示的代码中使用。Screenshot目前只使用默认构造函数和析构函数。
标签: c++ memory-leaks bitmap gdi+