最近写的转换程序,在debug版下跑了9个小时,最终崩溃,直接弹出对话框说:
应用程序发生异常,unknown software exception(0x80000003),位置为0x10212ad0.又在IDE状态下debug版跑了16个小时,最终弹出用户断点对话框,点按钮后定位在 DBGHEAP.c 文件的第338行:
- /* break into debugger at specific memory allocation */
- if (lRequest == _crtBreakAlloc)
- _CrtDbgBreak();
这段代码的作用是在达到指定内存分配次数时进行中断,以便于用户调试。这时lRequest == _crtBreakAlloc成立,lRequest =-1,其中,lRequest记录了当前内存分配次数,_crtBreakAlloc为用户设置的中断点(通过调用_CrtSetBreakAlloc进行设置),其初始值为-1L,即long型整数最大值。
问题是:即使用户没有设置中断点,那么随着程序的运行其内存分配次数总会有达到最大值的那一刻。
lRequest 初始化为_lRequestCurr,_crtBreakAlloc 初始化为-1,当程序启动时。每次 malloc(), lRequest (_lRequestCurr) 加1,经过一段时间运行后,lRequest (_lRequestCurr) 达到2,147,483,647。下一次再调用加1时则会数据溢出, 2,147,483,647 + 1 = -2,147,483,648,下次再加一则 lRequest (_lRequestCurr)从-2,147,483,648 加到 -1,这时_crtBreakAlloc 的值和lRequest (_lRequestCurr) 值都为-1,执行第二句 _CrtDbgBreak(),然后就出现用户设定断点提示,非IDE状态的debug版本则会直接报错崩溃。
这说明我们的程序存在非常频繁的内存分配,可以考虑使用内存池以提高效率。
解决办法有两个:
1. 改用RELEASE版。事实证明,release版本下不会出现该错误。
2. 少用malloc,new和delete动态分配内存;减少string和CString的使用,因为CString在内部实现中会调用new实现动态内存,想想啊,CString的字符串长度是可以任意变的,怎么会没有动态内存分配,又不可能每个CString都内置4G空间,对吧。(今天有看到帖子说,在debug版本中,cstring使用new和delete实现,但在release版本中小于512字节时使用4个不同大小的内存池实现,大于512字节时仍使用new和delete)
问题解决过程中参考了两个blog,向作者致谢:
1. http://blog.youkuaiyun.com/freefalcon/archive/2006/10/26/1352048.aspx
2. http://blog.youkuaiyun.com/sijigang/archive/2007/01/15/1483934.aspx
下面给出一个最简单的测试用例:
- #include <stdio.h>
- int main()
- {
- int* i;
- unsigned int j = 0;
- while (1)
- {
- i = new int;
- *i = 0;
- j++;
- delete i;
- }
- return 1;
- }