Win32 C++ 中的 DrawText 会增加内存使用量

Posted

技术标签:

【中文标题】Win32 C++ 中的 DrawText 会增加内存使用量【英文标题】:Memory usage increases with DrawText in Win32 C++ 【发布时间】:2016-05-10 11:12:58 【问题描述】:

我使用 MFC 实现了一个简单的游戏。它包含图像和格式化的文本。在测试时,我发现程序运行大约 7 分钟后没有问题,之后图像消失并且文本格式重置。为了确定问题,我重写了一个非常基本的版本,它只显示格式化的文本。但是问题仍然存在,我已经用谷歌搜索了一天,但问题仍然存在。这是我的 OnPaint 方法

    CPaintDC dc(this);

    CRect clientRect;
    GetClientRect(&clientRect);

    CDC bitmapDC;
    bitmapDC.CreateCompatibleDC(&dc);

    CBitmap bitmap;
    bitmap.CreateCompatibleBitmap(&dc, clientRect.Width(), clientRect.Height());
    bitmapDC.SelectObject(&bitmap);

    CBrush backgroundBrush;
    backgroundBrush.CreateSolidBrush(RGB(0xf8, 0xf8, 0xf8));
    bitmapDC.FillRect(&clientRect, &backgroundBrush);

    int SavedDc = bitmapDC.SaveDC();

    long nHeight = -MulDiv(20, GetDeviceCaps(bitmapDC, LOGPIXELSY), 72);
    HFONT myfont = CreateFont(nHeight, 0, 0, 0, FW_ULTRALIGHT, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
        CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, VARIABLE_PITCH, TEXT("Arial"));

    bitmapDC.SelectObject(myfont);
    SetBkMode(bitmapDC, TRANSPARENT);

    bitmapDC.DrawText(L"This shouldn't happen", &clientRect, DT_SINGLELINE | DT_CENTER | DT_VCENTER);

    dc.BitBlt(0, 0, clientRect.Width(), clientRect.Height(), &bitmapDC, 0, 0, SRCCOPY);

    bitmapDC.RestoreDC(SavedDc);
    backgroundBrush.DeleteObject();
    bitmap.DeleteObject();
    bitmapDC.DeleteDC();

我可以看到 Visual Studio 中的内存使用量逐渐增加。如果我注释掉 DrawText 部分,它就不会再增加了。难道我做错了什么?如何防止 DrawText 方法增加内存使用量?我也用图像测试过,这是同样的问题。我应该以某种方式释放或删除 DrawText 吗?任何帮助将不胜感激。

【问题讨论】:

你没有删除我的字体。 @JonathanPotter 你是对的,阻止了增长。只是一个后续问题,如果我想绘制图像,删除 CImage 对象是否也足够?我刚刚对其进行了测试,仅删除 CImage 并不能阻止增加。非常感谢您的帮助。 我在任何地方都看不到 CImage。 @JonathanPotter 我已将其注释掉以测试相同的事情是否仅发生在文本中。 【参考方案1】:

图像和字体消失是 GDI 资源泄漏的标志,而不是内存。

虽然泄漏内存非常糟糕,但泄漏资源更糟糕,因为它们非常有限。观察游戏任务管理器中的GDI Objects 列;当计数器达到 10,000 - 你就完成了。

仅删除持有 GDI 资源的 MFC 对象是不够的,您需要先从 DC 中取消选择它们(当前选择的对象无法释放)。

【讨论】:

有关工具和策略的信息,请参阅 Debugging a GDI Resource Leak。 这很有帮助,谢谢。但是有一个问题:如何取消选择?根据我从你最后一句话的理解,ReleaseDC 不会成功,对吧? @Revangelis - CDC::SelectObject() 返回一个指向先前选择的该类型对象的指针;您只需将其保存并选择回该 DC。但是,这可能已经通过 SaveDC() / RestoreDC() 调用在您的代码中完成。【参考方案2】:

以防被选入 DC 的对象无法删除, 为什么不严格处理?

bitmapDC.SelectObject(&bitmap);
 ↓
CBitmap* pbmold = bitmapDC.SelectObject(&bitmap);

(omission)

bitmapDC.SelectObject(pbmold); // addition
bitmap.DeleteObject();
bitmapDC.DeleteDC();

字体也一样……

【讨论】:

对不起。你在 savedc 中做到了。

以上是关于Win32 C++ 中的 DrawText 会增加内存使用量的主要内容,如果未能解决你的问题,请参考以下文章

win32 C++项目中的输入超时

win32 (C++) 中的动画和事件问题

Win32 (C++) 中的选项卡损坏

C++ Win32 窗口重叠事件

如何有效地杀死C ++(Win32)中的进程?

解决win10系统中调用DrawText时传入DT_ENDELLIPSIS仍然不显示省略号的问题