双缓冲文字输出内存泄露?怎么改?
本帖最后由 VisualEleven 于 2012-11-18 12:09:47 编辑 最近做一个监控界面,需要使用大字体刷新测量数据,出现故障时需要将字色变为红色
我定义了一个CColorStatic类
在OnPaint中写
CPaintDC dc(this);
CDC m_hdcMem;
CBitmap m_hBitmap;
if (m_hdcMem.CreateCompatibelDC(NULL) == 0)
{
m_hdcMem.DeleteDC();
return;
}
CRect rect;
GetClientRect(&rect);
if (m_hBitmap.CreateCompatibleBitmap(&dec, Rect.Width() + 1, rect.Height() + 1) == 0)
{
m_hBitmap.DeleteObject();
m_hdcMem.DeleteDC();
return;
}
m_hdcMem.SelectObject(&m_hBitmap);
CString strText = _T("");
GetWindowText(strText);
....
m_hdcMem.FillRect(&rect, m_pBrush);//填充黑色
m_hdcMem.SelectObject(&m_font); //使用大字体
m_hdcMem.SetTextColor(m_rgbText);
m_hdcMem.SetBkMode(TRANSPARENT);
m_hdcMem.DrawText(strText, rect, nFormat);
//nFormat是设置文字左中右的,用的DWORD dwStyle = GetStyle()
dc.BitBlt(0, 0, rect.Width(), rect.Height(), &m_hdcMem, 0, 0, SRCCOPY);
m_hdcMem.DeleteDC();
m_hBitmap.DeleteObject();
界面上有10个CColorStatic控件需要刷新,刷新频率为1秒一次
发现程序运行后,开头30秒左右内存使用一直没问题,之后大约4秒左右
程序使用内存增加4K的样子,时间久了之后,如果打开其他功能界面,
就会出现一些CColorStatic框变成了其他功能界面的图形,且在也不能刷新了
在调试过程中试过将刷新的timer禁用,内存一直不会增长。
试过将BitBlt这一句注释,发现内存也不会增长。。。。。!!!
现在就不知道是哪儿的问题了。
目标计算机是WinCE的。。。
高手帮看看
[最优解释]
m_hdcMem.SelectObject(&m_hBitmap);
m_hdcMem.SelectObject(&m_font); //使用大字体
需要将原值保留,退出时复原
[其他解释]
选入的位图和字体都要恢复
[其他解释]
if (m_hdcMem.CreateCompatibelDC(NULL)
为什么不是 dc ?
[其他解释]
SelectObject选择对象之后一个返回资源指针(上一次的资源指针)。
在结束的时候需要重新SelectObject这个资源指针。就是所谓的还原
这样才不会出现楼主所说的问题。
[其他解释]
试过的将它们保留,恢复,还是一样的
[其他解释]
你没有用多线程或者timeSetEvent()函数吧,因为DC是稀缺资源,同时申请可能不够用.
[其他解释]
后台是个线程获取各个点的数据,通过一个timer循环对每个Static进行SetWindowText操作
现在发现,时间长了之后,调试发现m_hdcMem中有个hDC—C的指针=0x000000000)...
问题是BitBlt屏蔽后为什么就不会吃掉内存了啊?我的内存释放有没有问题啊?
刷新的机制没有进行延时,循环体直接是一个接一个,没有延时,不过
在刷新内部有对数据的判断,有几十行的代码吧
[其他解释]
选入的位图和字体 试过都重新Select回去,还是一样的结果
schlafenhamster:
如果使用m_hdcMem.CreateCompatibelDC(dc)也是一样的结果
[其他解释]
BOOL ret=m_hBitmap.DeleteObject();
看看是不是真的。
[其他解释]
CDC m_hdcMem;
CBitmap m_hBitmap;
都是类成员?换成局部变量试试
[其他解释]
tiger:
重新选入老的字体和图片都测试过的,还是有问题的。
schlafenhamster:
嗯,下午去办公室试试,还有其他的函数都看看是不是正常返回
看有什么问题没有
mcmcmc :
是在OnPaint里面定义的局部变量
------其他解决方案--------------------
你不SelectObject原来的,你的这个操作m_hBitmap.DeleteObject();应该会调用失败
[其他解释]
完整代码
CPaintDC dc(this)
[其他解释]
额……手机上发不完
就是按照几位说的将选出的在bitblt后重新选入
然后bmp.deleteobject
m_hdcmem,deletedc
最后releasedc(&dc)
程序下载到wince板子后
用远程堆查看器看,发现堆一直增长
标记为fixed为大多数
在两个delete加变量接收结果都是true
[其他解释]
“最后releasedc(&dc)”
你把 CPaintDC release 了 ?
不要的吧
[其他解释]
难道是bug?
http://support.microsoft.com/kb/318622/en-us
[其他解释]
如果是微软bug,用
hDC = ::GetDC (m_hWnd);
CPaintDC::FromHandle(hDC)
不要用
CPaintDC dc(this),后者调用bug代码
[其他解释]
还有
http://support.microsoft.com/kb/819635/en-us
http://www.bluemcu.com/designstrategy/2011/1/6/111526_89.html
[其他解释]
好像也不是,看了CPaintDC(CWnd*)源码,也是hwnd调用,可能其他地方有什么问题.
[其他解释]
额。。。不是吧,我去试试
[其他解释]
CPaintDC::FromHandle(hDC)
改成
CPaintDC::Attach(hDC)不过估计也没有大用
方法不对,照理也不会频繁调用OnPaint(),只有WM_PAINT才会,是不是多线程SetWindowText()引起的? 如果可能work thread最好不要碰GUI函数.
还有最后一条路就是不用CDC,全部SDK
[其他解释]
我试了下
改成这种方式后会一直循环调用onpaint,界面死在那儿了。
[其他解释]
可以将m_hdcMem,m_hBitmap变成类成员变量,因为它们并不消耗DC资源,不用每次都建立删除,在OnCreate()的时候建立一下,析构或者OnDestroy()的时候删除,在OnPaint()的时候
m_hdcMem.DrawText(strText, rect, nFormat);
dc.BitBlt(0, 0, rect.Width(), rect.Height(), &m_hdcMem, 0, 0, SRCCOPY);
甚至可以缓存几套hdcMem,一套用于正常字体,一套用于异常字体,这样SelectObject()也不用每次做了.
[其他解释]
有人说是SetWindowText的问题。。。。
我试了下,换成用updatedata的方式更新
onPaint这里面完善了下
{
CPaintDC dc(this);
CDC m_hdcMem;
CBitmap m_hBitmap;
if (m_hdcMem.CreateCompatibelDC(NULL) == 0)
{
m_hdcMem.DeleteDC();
return;
}
CRect rect;
GetClientRect(&rect);
if (m_hBitmap.CreateCompatibleBitmap(&dec, Rect.Width() + 1, rect.Height() + 1) == 0)
{
m_hBitmap.DeleteObject();
m_hdcMem.DeleteDC();
return;
}
CBitmap *m_oldBMP = m_hdcMem.SelectObject(&m_hBitmap);
CString strText = _T("");
GetWindowText(strText);
....
m_hdcMem.FillRect(&rect, m_pBrush);//填充黑色
CFont *m_OldFont = m_hdcMem.SelectObject(&m_font); //使用大字体
m_hdcMem.SetTextColor(m_rgbText);
m_hdcMem.SetBkMode(TRANSPARENT);
m_hdcMem.DrawText(strText, rect, nFormat);
//nFormat是设置文字左中右的,用的DWORD dwStyle = GetStyle()
dc.BitBlt(0, 0, rect.Width(), rect.Height(), &m_hdcMem, 0, 0, SRCCOPY);
m_hdcMem.SelectObject(m_OldFont);
m_hdcMem.SelectObject(m_OldBMP);
m_hBitmap.DeleteObject();
m_hdcMem.DeleteDC();
}
内存泄露明显少了很多
但是还是有 。。。
天啦。。。。。
[其他解释]
应该是m_hdcMem.SelectObject(&m_hBitmap); 这个丢的,这个你没有还原回去,删除不掉的
CBitMap *old = m_hdcMem.SelectObject(&m_hBitmap);
......
m_hdcMem.SelectObject(old );
m_hdcMem.DeleteObject();
[其他解释]
现在在类里面增加了要显示的TXT变量和一个类函数SHOWTEXT
将OnPaint中的GetWindowText去掉,和TXT变量联系起来进行写DC
在SHOWTEXT中接收并修改TXT变量
调用Invalidate(FALSE)强制刷新界面,就没有泄露了
但是如果调用Invalidate(TRUE)就还有泄露。。。。
不知道为什么,有谁知道吗?
PS
在WIN32环境下用同样的类,
SetWindowText发现居然不显示带色的大字体,还是显示的默认的字体和颜色
调试发现完全就没有调用OnPaint。。。。
用其他窗口遮盖后,引起界面刷新就可以看到Paint后的界面了,不过马上又回到默认了
那就是说SetWindowText在WinCE和Win32下的机制是不同的?
还是说所有的问题都是VS 2008的问题?
弄个EVC或VS2005之类的在试试
[其他解释]
我现在是单独的一个小程序,仅仅只实现用Timer
在timr中Random数据,然后显示到文本控件中
还有程序是都选入、选出了的了
。。。。开头的双缓冲程序是有点问题的,后来我改了
[其他解释]
InvalidateRect()如何?估计还是程序内部问题,多线程之间传递消息有不干净的内存,并且在windows消息中传播.还有有些字体不是所有系统都支持,比如在win7下有些字体会是乱码...
[其他解释]
.cpp
// ColorStatic.cpp Version 1.0
///////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "ColorStatic.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
///////////////////////////////////////////////////////////////////////////////
// CColorStatic
BEGIN_MESSAGE_MAP(CColorStatic, CStatic)
//{{AFX_MSG_MAP(CColorStatic)
ON_WM_PAINT()
ON_WM_ERASEBKGND()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
///////////////////////////////////////////////////////////////////////////////
// constructor
CColorStatic::CColorStatic()
{
m_rgbText = GetSysColor(COLOR_BTNTEXT);
m_rgbBackground = GetSysColor(COLOR_BTNFACE);
m_bBold = FALSE;
m_ShowText= _T("");
m_bTrans= TRUE;
m_Align= SS_CENTER;
}
///////////////////////////////////////////////////////////////////////////////
// destructor
CColorStatic::~CColorStatic()
{
TRACE(_T("in CColorStatic::~CColorStatic\n"));
}
///////////////////////////////////////////////////////////////////////////////
// OnPaint
void CColorStatic::OnPaint()
{
CPaintDC dc(this); // device context for painting
CDC m_hdcMem;
CBitmap m_hBitmap;
CFont m_font;
CBrush m_Brush;
CString sShowText;
if (m_hdcMem.CreateCompatibleDC(NULL) == 0) //Create Fail
{
//m_hdcMem.DeleteDC();
return;
}
CRect rect;
GetClientRect(&rect);
if (m_hBitmap.CreateCompatibleBitmap(&dc ,rect.Width(), rect.Height()) == 0) //Create Fail
{
//m_hBitmap.DeleteObject();
m_hdcMem.DeleteDC();
return;
}
if (!m_font.CreateFont(m_iFontSize, 0, 0, 0, 0, FALSE, FALSE, 0,
GB2312_CHARSET, 0, 0, 0, 0,m_sFontName)) //Create Fail
{
m_hBitmap.DeleteObject();
m_hdcMem.DeleteDC();
return;
}
if (!m_Brush.CreateSolidBrush(m_rgbBackground)) //Create Fail
{
m_font.DeleteObject();
m_hBitmap.DeleteObject();
m_hdcMem.DeleteDC();
return;
}
CBitmap *m_OldBMP =m_hdcMem.SelectObject(&m_hBitmap);
CFont * m_OldFont = m_hdcMem.SelectObject(&m_font);
GetWindowText(sShowText);
UINT nFormat = 0;
if ((m_Align & SS_CENTER) >0)
nFormat
[其他解释]
这个类的代码如下
.h
// ColorStatic.h
///////////////////////////////////////////////////////////////////////////////
#ifndef COLORSTATIC_H
#define COLORSTATIC_H
/////////////////////////////////////////////////////////////////////////////
// CColorStatic window
class CColorStatic : public CStatic
{
// Construction
public:
CColorStatic();
virtual ~CColorStatic();
// Attributes
public:
void SetBackgroundColor(COLORREF rgb, BOOL bRedraw = TRUE);
void SetTextColor(COLORREF rgb, BOOL bRedraw = TRUE);
void SetFont(LPCTSTR lpszFaceName, int nPointSize);
void SetTrans(bool bTranslate);
void ShowText(LPCTSTR sText);
void SetAlign(DWORD dAlign);
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CColorStatic)
protected:
// virtual void PreSubclassWindow();
//}}AFX_VIRTUAL
// Implementation
protected:
COLORREFm_rgbText;
COLORREFm_rgbBackground;
BOOLm_bBold;
BOOLm_bTrans;
intm_iFontSize;
CStringm_ShowText;
DWORDm_Align; //SS_CENTER SS_LEFT SS_RIGHT
LPCTSTRm_sFontName;
int GetFontHeight(int nPointSize);
// Generated message map functions
protected:
//{{AFX_MSG(CColorStatic)
afx_msg void OnPaint();
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif //COLORSTATIC_H
[其他解释]
= DT_LEFT;
else if ((m_Align & SS_RIGHT) > 0)
nFormat
[其他解释]
= DT_CENTER;
else if ((m_Align & SS_LEFT) > 0)
nFormat