如果处理不当,Windows API 资源可能会导致内存泄漏。无论在这个问题中是否如此,我假设它是相关的。尽管我展示了我如何确定问题的来源,但我无法解决它。
我有两种使用 Win32 API 的静态类控件,它们在我的类中被抽象出来:
Label
LinkLabel
问题:每当我添加这两个控件时,当我同时启用 setFont() 或 setHoverColor() 行时,Visual Studio 2017 的诊断工具显示进程内存 (MB) 从 3MB 增加到 11MB,最终我的 GUI 空间中的所有内容都消失了 - - 消失了,就像一些知名书店一样。
这段代码很好(3MB 在进程内存中保持相同的恒定速率):
// Linked Label
myLinkLabel.init("http://www.google.com", 50, 450);
myLinkLabel.setColor(0, 0, 255);
myLinkLabel.onClick(lbl_Click);
myLinkLabel.setFont("Arial", 40, true);
//lbl.setHoverColor(255, 0, 0);
// label
myLabel.init("A regular static label", 0, 0);
myLabel.setColor(0, 255, 0);
myLabel.setFont("Arial", 40);
//myLabel.setHoverColor(255, 0, 0);
下一个代码取消对最后一行的注释。将鼠标悬停在 myLabel 上,出现红色高亮颜色后,Process Memory 的 3MB 增加到 7MB+。它坐了一会儿,然后上升到 9MB+。所以,这里面有些不对劲。
// Linked Label
myLinkLabel.init("http://www.google.com", 50, 450);
myLinkLabel.setColor(0, 0, 255);
myLinkLabel.onClick(lbl_Click);
myLinkLabel.setFont("Arial", 40, true);
//lbl.setHoverColor(255, 0, 0);
// label
myLabel.init("A regular static label", 0, 0);
myLabel.setColor(0, 255, 0);
myLabel.setFont("Arial", 48);
myLabel.setHoverColor(255, 0, 0);
所以,让我们深入研究我的 setHoverColor():
void Label::setHoverColor(const BYTE red, const BYTE blue, const BYTE green)
{
m_hoverColorEnabled = true;
m_hoverColor = RGB(red, green, blue);
}
好的,上面的代码没什么特别的。这告诉我查看 WndProc。
这个静态控件使用的事件是 WM_SETCURSOR。
case WM_SETCURSOR:
{
HWND m_handle = (HWND)wParam;
// Label
for (int i = 0; i < frm.getLabelControlCount(); i++)
{
if (frm.getLabelControl(i).getHandle() == m_handle)
{
if (frm.getLinkLabelControl(i).isLink())
{
// Set hover color to link
if (frm.getLabelControl(i).isHoverColorEnabled())
frm.getLabelControl(i).setColor(frm.getLabelControl(i).getHoverColor());
// Update cursor to hand
SetClassLongPtr(frm.getLabelControl(i).getHandle(), GCLP_HCURSOR, (LONG_PTR)frm.getLabelControl(i).getHoverCursor());
}
}
else
{
// Set link to blue and use default arrow
if (frm.getLabelControl(i).isHoverColorEnabled())
frm.getLabelControl(i).setColor(0, 0, 255);
SetClassLongPtr(frm.getLabelControl(i).getHandle(), GCLP_HCURSOR,
(LONG_PTR)LoadCursor(NULL, IDC_ARROW));
}
}
注释这部分代码时,进程内存保持不变,为 3MB。取消注释此部分时,进程内存会增加。所以,这是导致问题的主要代码。
这部分代码基本上是根据当前鼠标悬停状态更新标签的文本颜色。未悬停时为蓝色,悬停时为红色。
setColor() 是以下代码:
void Label::setColor(const COLORREF color)
{
m_foreColor = color;
setFont(m_fontName, m_fontSize, m_bold, m_italic, m_underlined);
}
它还调用 setFont() 来更新它:
bool Label::setFont(const std::string &fontName, const int size, const bool bold,
const bool italic, const bool underlined)
{
DWORD dwItalic;
DWORD dwBold;
DWORD dwUnderlined;
SIZE linkSize;
dwItalic = (italic) ? TRUE : FALSE;
dwBold = (bold) ? FW_BOLD : FW_DONTCARE;
dwUnderlined = (underlined) ? TRUE : FALSE;
m_font = CreateFont(size, 0, 0, 0, dwBold, dwItalic, dwUnderlined, FALSE,
ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH | FF_SWISS, fontName.c_str());
SendMessage(m_handle, WM_SETFONT, WPARAM(m_font), TRUE);
// Calculate the correct width and height size
HDC hDC = GetDC(m_handle);
SelectFont(hDC, m_font);
GetTextExtentPoint32(hDC, m_text.c_str(), (int) m_text.length(), &linkSize);
setSize(linkSize.cx, size);
// Store font information
m_fontName = fontName;
m_fontSize = size;
m_bold = bold;
m_underlined = underlined;
m_italic = italic;
return true;
}
我的猜测是,这是创建字体并根据每次悬停重新创建字体的大量更新。我的理由是它不会更新字体颜色,除非再次设置字体。虽然我在不久的将来看到了这个空间,但我是否忘记在这里删除资源或其他东西?欢迎任何想法。很确定这也可以解决 LinkLabel 问题。
最佳答案
您的基本问题是您不断生成新字体而从不发布旧字体。
每次调用 setfont 时,您都会分配并选择一种新字体。但是当您在 HDC 中选择新字体时,您永远不会清理旧字体。
SelectFont 返回您需要的先前选择的字体(除非它是库存字体)来执行 DeleteFont。
此外,您在 GetDC 调用中有更大的资源泄漏 - getDC 的 MS 文档建议您在完成使用后使用 releaseDC。
据我所知,不需要重置字体只是为了重置颜色。
关于c++ - 为什么将鼠标悬停在静态 Win32 控件上会增加内存并删除我的 GUI?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44951417/