递归致使的StackOverflow的分析

递归在多层次遍历时尤其重要,这里咱们不讲递归的实现,来谈谈递归的内存占用状况。多线程

以下代码,当咱们运行时很简单,StackOverflowException瞬间抛出;这里确实是“瞬间”出错了,线程堆栈溢出;spa

首先咱们要理解,一个程序是在一个进程下运行的,进程下能够有不少线程执行,可是每个线程能占用的内存控件是有限的,大约1M,当一个线程占用超过1M时,就会StackOverflow了;存放在线程堆栈上的有方法中的值类型变量,和引用变量的指针地址。理解这些能帮咱们分下,递归为何致使StackOverflow了。线程

static void Main(string[] args)
{
      Main(args);
}

这里咱们作一个简单的分析,不考虑不重要的因素:指针

首先,线程执行Main方法,首先方法总没有值类型变量,只有数据args,全部只有args的指针地址存放在线程堆栈上,占4byte,Main中有调用Main方法,如此递归调用,就至关于(4+4+4……+4)bytes,最终达到1M,致使StackOverflow异常。有CLR抛出异常。code

固然这里线程执行方法只是一个简单的分析,实际状况很复杂,好比,进入方法,会有一个专门的表维护方法信息,方法的返回地址,参数,局部变量,这些都占用线程堆栈空间,方法返回时,全部方法占用的内存被释放。而上述递归,永远不存在方法返回,因此资源不会被释放,最终抛出异常。blog

 

若是说上述很简单理解,那咱们加俩行代码:递归

 

static void Main(string[] args)
        {
            GC.Collect();
            GC.WaitForFullGCComplete();
            Main(args);
        }

这样执行方法,这个代码是我从某论坛的一个版主那里看来的,他说这样就不会致使StackOverflow了,结果下面的一群人深信不宜,我感受递归确定资源耗尽,只是GC不能回收线程堆栈内存,可是当我在代码上运行时,上述代码确实不报错,一直运行着,当时纳闷难道我理解错误,这不科学!我一直等着,果真过了1分钟多,我期待的StackOverflow出现了,内心窃喜。进程

可是我自己也不是很理解,为何加了上面的两句话致使,要等那么久才移除,很奇怪。我问了问别人,结果实验了一下,将GC代码去掉,仅仅加一个Thread.Sleep(5),也会致使很长时间才抛出异常,费解中,最后我写了以下代码:内存

static int a = 0;
static void Main(string[] args)
        {
            a++;
            Console.WriteLine(++a);
            Main(args);
        }

我看下方法递归多少次,我电脑上是a=12万多,也就是最终方法递归了12万屡次抛出了StackOverflow,全部上面的Thread.Sleep(5)执行长时间才报错也能够的出结论了,每一递归一次方法听5毫秒,递归1万次就是50秒,因此,结论不是GC回收影响递归长时间不报错,而是,每次执行GC,线程Sleep的时间,让我感受长时间不报错。资源

 

上面问题自己没有多大意义,仅仅做为笔记记录一下,一样本身也更深刻理解了内存占用。

相关文章
相关标签/搜索