避免堆栈溢出

案例

最近在做一个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编程中的消息响应函数),其中也避免有太大的局部变量。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值