由于C#是一种托管语言,它的垃圾回收机制(GC)是由.net平台负责的,加之C#语言并没有指针,所以我们在使用过程中极少会考虑到内存使用状况以及项目在运行过程中是如何进行内存管理的。但是,C#只是在内存管理方面对程序员隐藏了,并不代表它不涉及这些东西,甚至其内部内存管理或许比自己手动管理更加复杂。笔者从内存四区(栈区、堆区、全局区、代码区)的角度对C#语言中常见的几种情况分析其内存,但是只是从现象上根据C/C++类似的状况进行推断理解,其底层无法得知,而且针对内存分区也有不同的观点,所以纯属个人体会,欢迎指正。
场景分析:
- 值类型定义:int a=10; 这个应该和C中类似,a在代码区,10存放在a在栈中开辟的内存里;
- 引用类型:Person p=new Person(); p存放在代码区,new Person()产生对象存放在堆区,由.net平台的垃圾回收机制(GC)管理,将堆区对象的地址存放在p在栈区开辟的内存里;
- 全局变量、常量、静态类和静态成员(静态变量、静态方法),都存放在全局区,而它们的地址放在声明时变量(在代码区)开辟在栈区的内存中。(这些地址都是在程序运行时最先压栈的,这点很重要)
说明:
- 全局变量和静态类、常量、静态成员,都是在全局区,但是它们的地址仍放在栈区,为什么会保存住呢?因为在.net程序编译时这些静态和全局都是最先编译的,所以最先压栈,那么也就只能等程序结束时才会弹栈,所以全程可用。缺点就是启动慢、编译时间长;当然优点也有,如常说的,静态类常用于窗体传值和实现单例模式,这就得益于它的一次编译全程可用。
- 定义在栈中的数据,如值类型数据,在所在方法中执行完毕就会被弹栈,如果有些地址也在这个方法中,那么也会弹栈,这就是为什么在其他方法中不能再访问其他方法中定义的对象。而这些对象岂不是“失联”了,不就内存泄漏了?其实不会,这就是.net平台的垃圾回收机制(分代进行回收),保证内存充足。
- 全局和静态上面说过,会在程序运行结束时才会被释放和回收,所以应限制使用全局变量、常量、和静态变量和静态类,否则程序负荷高,这也是为什么称C中的全局变量为“灰色地带”,因为对于C这么对内存严格控制的语言来说,确实是“灰色地带”。所以据说Java中就不能定义全局变量。