现在的位置: 首页 > 综合 > 正文

内存泄露解决记录——窗口资源释放

2013年10月15日 ⁄ 综合 ⁄ 共 2549字 ⁄ 字号 评论关闭

前段时间在解决代码的内存泄露问题,解决了部分内存泄露问题。

 

http://blog.csdn.net/enjolras/archive/2011/01/05/6117628.aspx

这篇文章起到了很好的指引作用,让我对MFC里宏观方面的释放有了一定了解。

总结一下就是:

1、推荐用DestroyWindow来销毁窗口(或者从窗口派生的对象)。

2、重载PostNcDestroy函数通过调用基类的PostNcDestroy函数,如:Cwnd::PostNcDestroy,以及通过delete this来调用析构函数(析构函数中处理窗口类中的需要delete的成员)来自动清理。

 

此外比较重要的几点(需要好好理解的几点):

1、Windows对象(CWnd派生类的对象)既代表一个C++对象(在应用程序的堆中分配)也代表了一个HWND(由窗口管理器在系统资源里分配)。释放分为如下部分,C++对象的释放,HWND的释放,以及C++对象与与之关联的句柄的分离过程(detach)。

 

2、当销毁一个Windows窗口时,最后发送给此窗口的Windows消息是WM_NCDESTROYCWnd对此消息的缺省处理(CWnd::OnNcDestroy)会将C++对象与HWND分离,并调用虚函数PostNcDestroy

 

3、缺省的CWnd析构函数会在m_hWnd不为空的情况下调用DestoryWindow,但这不会导致无穷递归,因为此句柄在清除阶段将会处于分离状态并为空。注意是缺省的,若重载了析构函数将不会调用。

 

4、CWnd::PostNcDestroy也会在大部分Create调用的执行部分被调用,如果错误发生的话。

 

5、CWnd::PostNcDestroy的缺省操作是什么也不做,这适合于那些分配在堆栈或者嵌在其他对象里面的窗口对象。这不适合于那些设计来分配在堆上的窗口对象(不嵌在其他C++对象中)。所以重载分配在堆上的窗口对象需要重载PostNcDestroy并在此 函数中delete this,否则析构函数不会被自动调用,而分配在栈上会自动回收,不需要手动释放。

 

6、对于一个不执行自动清理的对象,在调用DestroyWindow之后,这个C++对象仍然存在,但是m_hWnd会为空。对一个执行自动清理的对象,在调用DestroyWindow之后,此C++对象就不存在了,它被PostNcDestroy的自动清理执行过程里的delete操作符释放。(区别就在于有没有delete this,如果你喜欢,也可以不重载PostNcDestroy,调用pWnd->DestroyWindow再delete pWnd;)。

 

补充知识点:

 

1、HWND,窗口句柄。

内核对象的数据结构仅能够从内核模式访问,应用程序必须使用API函数访问内核对象。调用函数创建内核对象时,函数会返回标识此内核对象的句柄。此句柄是一个能够被进程中任何线程使用的一个不透明的值,许多API函数需要以它为参数,以便系统知道要操作哪一个内核对象。

 

2、引用计数,某些系统资源(内核对象)可为多个进程所有,用引用计数来记录有多少个进程引用了这个资源,如果没有释放会导致引用计数错误,引发系统资源内存泄露。

 

3、系统资源错误比堆内存泄露有更为严重的后果。

 

4、所有Handle是Create出来的都需要CloseHandle,窗口句柄不用显式的释放。窗口被销毁的时候窗口句柄就会被释放了。哪些需要哪些不需要请MSDN。

 

5、DestroyWindow Function说明

--------------------------------------------------------------------------------
The DestroyWindow function destroys the specified window. The function sends WM_DESTROY and WM_NCDESTROY messages to the window to deactivate it and remove the keyboard focus from it. The function also destroys the window's menu, flushes the thread message queue, destroys timers, removes clipboard ownership, and breaks the clipboard viewer chain (if the window is at the top of the viewer chain).

If the specified window is a parent or owner window, DestroyWindow automatically destroys the associated child or owned windows when it destroys the parent or owner window. The function first destroys child or owned windows, and then it destroys the parent or owner window.

 

DestroyWindow 函数销毁特定的窗口。这个函数发送WM_DESTROY跟WM_NCDESTROY消息去使它失去焦点、移除键盘焦点。这个函数也销毁窗口菜单,清洗消息队列,销毁时间事件,移除剪贴板所有权,和打破剪切板查看链(如果这个窗口在查看链的顶端)。

如果这个特定的窗口是一个父窗口或拥有者象的窗口,DestroyWindow函数自动销毁关联的子窗口或者被拥有窗口,然后再销毁父窗口与拥有者窗口。

 

 以下是VC中一些“特别”的内存地址,指针变量要记得初始化

0xcdcdcdcd - Created but not initialised

0xdddddddd - Deleted

0xfeeefeee - Freed memory set by NT's heap manager

0xcccccccc - Uninitialized locals in VC6 when you compile w/ /GZ

0xabababab - Memory following a block allocated by LocalAlloc()

 

抱歉!评论已关闭.