栈(stack)是一种数据结构,栈中每个指针(当运行到那个变量时)会指向堆中的某一内存区域或说是空间。它是以先进后出为原则的。

堆(heap)就直接是内存区域了,它是为了栈的引用而开发内存的。通常内置变量就是值类型是被保存在栈中的。其他由.NET框架(Framework)提供的,或者是我们自己定义的对象即引用类型,一般被创建在堆中并将由栈中变量引用。

那么它们运行时的释放是怎样呢?首先刚才说了,栈中会有指针指向堆,其实那叫栈帧(当一个函数被调用时,栈就去堆中借一块内存给它),当函数返回时,栈帧被释放,栈帧中的对象超出作用域而被销毁。这就是一个变量的生命周期了,一只工蜂的生命就是他完成了采蜜工作。而堆中的对象是在没有栈帧指向它的时候,也就是工蜂采完蜜了,蜂王产下卵之后就结束生命了。之后堆中的对象就通过CLR垃圾回收系统销毁。

当一个方法被调用,调用栈会分配一块空间成为栈页,用来保存被调用方法的下一条指令的返回地址。也就是说它会将调用方法之后会产生什么的返回地址发给被调用方法的参数以及被调用方法的所有局部变量。所以“展开调用栈”就是指找到被调用方法的返回地址并强制方法返回,在调用方法的方法中寻找catch语句或其他处理异常的语句来处理异常。在找到异常处理代码之前,栈要“展开”很多被调用的方法。如果最终栈展开到main方法儿还是没找到异常处理代码,默认的异常处理就会被调用,整个程序被终结,栈中的变量和栈帧被销毁,程序终止。

其实如果程序找到了异常处理的代码就会从那段代码开始继续,而不是从抛出异常的地方,或是从调用了抛出异常方法的方法(除非这个方法包含异常处理代码),一定拿栈页被展开,他就被释放。

posted on 2010-07-15 16:43  SQnet  阅读(1046)  评论(2)    收藏  举报