在前一段时间的项目中,我们遇到了一个问题。那就是在主程序中运行一切正常,但在Shell扩展中执行,某些极端的情况系统会崩溃,而且没有任何提示。是什么问题呢?想了很多种可能,但我想极有可能是堆栈溢出。因为主程序的堆栈如果没有修改编译选项,应该是1M;但Shell扩展实际上只是运行explorer的一个线程空间内,其堆栈应该小得多。
最多我们找出了问题所在,因为程序需要搜集目录及文件信息,用到了递归的方式遍历整个目录树,其中传递了一个大对象作为作为参数(以引用的方式进行传递的),但我发现,在传递的过程中实际上需要生成一个临时对象,最后通过修改,避免了临时对象的产生。再运行程序,发现还是有问题,但递归层次加深了。
看来的确是堆栈溢出。接下来,我们又发现了一个大对象产生的根源:WIN32_FIND_DATAW(因为我们是UNICODE编码),将它改成了从堆上分配。再次运行程序,发现还是有问题,但递归层次更深了。
为什么还会溢出呢?最后发现了一个一直视而未见的大对象:
if(error occoured)
{
CReportItem reportItem;
....
}
直到后来才知道, 在函数中只要声明了变量,即便你不执行到相应的路径,但它一样要占堆栈空间。VC的编译器会在调用时一次性分配足够的堆栈空间.
又将它分配在堆上,问题解决。
可见在递归时,大对象可能带来很多问题,严重时会导致程序崩溃。同时过深的归递层次也会严重影响效率,适当的时候,我们应该改造递归算法,用循环来作为替代品。
最多我们找出了问题所在,因为程序需要搜集目录及文件信息,用到了递归的方式遍历整个目录树,其中传递了一个大对象作为作为参数(以引用的方式进行传递的),但我发现,在传递的过程中实际上需要生成一个临时对象,最后通过修改,避免了临时对象的产生。再运行程序,发现还是有问题,但递归层次加深了。
看来的确是堆栈溢出。接下来,我们又发现了一个大对象产生的根源:WIN32_FIND_DATAW(因为我们是UNICODE编码),将它改成了从堆上分配。再次运行程序,发现还是有问题,但递归层次更深了。
为什么还会溢出呢?最后发现了一个一直视而未见的大对象:
if(error occoured)
{
CReportItem reportItem;
....
}
直到后来才知道, 在函数中只要声明了变量,即便你不执行到相应的路径,但它一样要占堆栈空间。VC的编译器会在调用时一次性分配足够的堆栈空间.
又将它分配在堆上,问题解决。
可见在递归时,大对象可能带来很多问题,严重时会导致程序崩溃。同时过深的归递层次也会严重影响效率,适当的时候,我们应该改造递归算法,用循环来作为替代品。
Trackback: http://tb.blog.youkuaiyun.com/TrackBack.aspx?PostId=596710