避免堆栈溢出

来源:互联网 发布:淘宝收藏 猪八戒网 编辑:程序博客网 时间:2024/04/30 22:08

案例

最近在做一个Windows程序,其中有个消息处理函数,大概是这样的:

BEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)ON_MESSAGE(WM_MY_MESSAGE, &CMainFrame::OnMyMessage)END_MESSAGE_MAP()LRESULT CMainFrame::OnMyMessage(WPARAM wp, LPARAM lp){char sBuf[2048]; …….省略其它处理SendMessage(WM_ANONYTHER_MSG, sBuf, 0);}

在OnMyMessage中省略了其它代码,只保留了两个关键的地方。一个为其内部定义了一个局部变量sBuf,其大小为2K,另一个为调用SendMessage发送另一个消息。

测试中发现堆栈溢出的现象,而崩溃的地方就在OnMyMessage里。这个现象比较奇怪,因为OnMyMessage并没有其它地方有直接的函数调用,只有这一个消息响应的入口。而发送消息的地方也都是在其它线程里通过SendMessage发送的。而SendMessage是同步消息,要等到该消息处理完成后才会返回。因此不应该出现函数重入的情况。

分析

通过观察调用栈发现,OnMyMessage确实重入了多次,而其中的局部变量又比较大,从而导致了堆栈溢出。

那么问题来了,既然OnMyMessage没有递归调用,那么为什么会像递归调用一样被重入了多次呢?原因就出在OnMyMessage里调用了SendMessage(WM_ANONYTHER_MSG)。

实际上SendMessage之后,在主线程阻塞等待WM_ANONYTHER_MSG响应时,还是可以再继续处理消息队列上的其它消息的。而如果此时消息队列上有大量的WM_MY_MESSAGE,而WM_ANONYTHER_MSG的响应又确实比较慢时,那么主线程就会不断的处理WM_MY_MESSAGE,从而重复的调用OnMyMessage,造成了一种类似递归调用的现象。最终导致堆栈溢出。

此问题的修改方法也比较简单,只需将OnMyMessage里的局部变量改为动态申请即可:

LRESULT CMainFrame::OnMyMessage(WPARAM wp, LPARAM lp){char* sBuf = new char[2048]; …….省略其它处理SendMessage(WM_ANONYTHER_MSG, sBuf, 0);}

小结

1.      编程时尽量避免显示递归调用。如果确实需要用到显示递归调用,需保证局部变量不能太大。

2.      需注意一些可能会发生隐式递归调用的地方(比如Windows编程中的消息响应函数),其中也避免有太大的局部变量。


0 0
原创粉丝点击