避免堆栈溢出
来源:互联网 发布:淘宝收藏 猪八戒网 编辑:程序博客网 时间: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编程中的消息响应函数),其中也避免有太大的局部变量。
- 避免堆栈溢出
- 10.1.1避免尾递归的堆栈溢出
- 堆栈溢出
- 堆栈溢出
- 堆栈溢出
- 堆栈溢出
- 堆栈溢出
- 堆栈溢出
- 堆栈溢出
- 堆栈溢出
- 堆栈溢出
- 堆栈溢出
- 堆栈溢出
- 堆栈溢出
- 堆栈溢出
- 堆栈溢出基础教程
- 堆栈溢出系列讲座
- XSL堆栈溢出问题
- 图管够!灌篮高手、女儿国…阿里日_这帮程序员太会玩了!
- Hey guys
- java 调用 vbs 操作excel
- ClosedXML 内存泄漏或OutOfMemory错误的原因
- boost库生成文件命名和编译
- 避免堆栈溢出
- [bzoj3156] 防御准备 DP斜率优化
- js, jquery获取select标签选中的值
- 案例研究:利用Grails搭建Feedlr.com网站
- Android Things SDK用法之SPI篇
- Viewpager+Fragment去除页面切换时的滑动翻页效果
- 前端资源
- lucas定理(hdu3037,)
- 千万级别数据表,单列索引和多列索引性能对比