虽然在.Net Framework 中我们不必考虑内在管理和垃圾回收(GC),但是为了优化应用程序性能我们始终需要了解内存管理和垃圾回收(GC)。另外,了解内存管理可以帮助我们理解在每一个程序中定义的每一个变量是怎样工作的。
这一节介绍栈的基本工作原理。
1.引用类型永远存储在堆里。
2.值类型和指针永远存储在它们声明时所在的堆或栈里。
栈:如第一节所说,在代码运行时负责跟踪每一个线程的所在(什么被调用了)。你可以把它想象成一个线程“状态”,而每一个线程都有它自己的栈。当我们的代码执行一次方法调用,线程开始执行寄存在方法(method)表里的JIT编译过的指令,并且把该方法的参数存放到当前线程栈里。然后,随着代码的执行每遇见方法中的变量,该变量都会被放到栈的最上面,如此重复把所有变量都放到栈上,当然引用类型只存放指针。
为了方便理解,让我们看代码与图例。
执行 下面的方法:
下面是栈里发生的情况. 有必要提醒的是,我们现在假设当前代码产生的栈存储会放到所有既有项(栈里已经存储的数据)之上。一旦我们开始执行该方法,方法参数pValue会被放到栈上(以后的文章里会介绍参数传递)。
注意:方法并不存在栈里,图只是为了阐述原理而放的引用。
下一步,控制(线程执行方法)被传递到寄存在方法类型表里的AddFive()方法对应的指令集中。如果方法是第一次被触发,会执行JIT编译。
随着方法的执行,栈会分配一块内存给变量result存放。
方法执行完成,返回result。
该次任务在栈里所占的所有内存将被清理,仅一个指针被移动到AddFive()开始时所在的可用内存地址上。接着会执行栈里AddFive()下面一个方法(图里看不到)。
在这个例子当中,变量result被放到了栈里。事实上,方法体内每次定义的值类型变量都会被放到栈里。
当然值类型有时候也会被放到堆里,我们将会在下一节提到。
栈可以想像成一个严格顺序执行的序列,不允许跳跃穿插访问。栈有自我清理功能。本文以执行一个简单C#方法为例阐述了栈的基本工作原理。下一节继续介绍堆栈工作原理以及一个更复杂一些的例子。
译文连接:https://blog.csdn.net/leewhoee/article/details/16934737
原文链接:https://www.c-sharpcorner.com/article/C-Sharp-heaping-vs-stacking-in-net-part-i/