一 C#内存分配
在应用程序与操作系统之间有一个”中间人”——公共语言运行时(Common Language Runtime,CLR)。它为应用程序提供内`存管理,线程管理和远程处理等核心服务。CLR是应用程序的托管环境。
CLR在运行时管理着一段内存地址空间(虚拟地址空间,在运行中会映射到物理内存地址中),CLR将内存划分为线程堆栈,GC堆,大对象堆三个区域。
线程堆栈(栈)用于分配值类型实例。栈由操作系统进行管理,不受GC管理,当值类型不在其作用域(主要是指其所在函数内)时,其所占栈空间自动释放。栈的执行效率是非常高。GC堆(堆)用于分配小对象实例。所谓小对象就是大小小于85000字节的实例对象。GC堆分三代垃圾进行管理,当进行GC操作(垃圾回收)时,垃圾收集器会对GC堆进行压缩回收。大对象堆(LOH)用于分配大对象实例。大对象就是大小小于85000字节的实例对象。大对象分配在LOH上,不受GC控制,不会被压缩,只有在完全GC回收时才会被回收。
二 C#数据类型
C#是强类型语言,在C#程序中每个变量和对象都要声明类型。C#的数据类型可以分为值类型和引用类型。
C#中值类型包括三种:简单类型,枚举类型和结构类型。
值类型分类 |
类型 |
长度(位) |
|
简单类型 |
整型 |
sbyte (有符号字节型) |
8 |
byte (无符号字节型) |
8 |
||
char (字符型) |
16 |
||
short (短整型) |
16 |
||
ushort (无符号短整型) |
16 |
||
int (整型) |
32 |
||
uint (无符号整型) |
32 |
||
long (长整型) |
64 |
||
ulong (无符号长整型) |
64 |
||
浮点型 |
float(单精度) |
精度为7位 |
|
double(双精度) |
精度为15~16位 |
||
小数型 |
decimal |
精度为28~29位 |
|
布尔型 |
bool |
逻辑真或逻辑假 |
|
枚举型 |
枚举型 |
enum |
|
结构型 |
结构型 |
struct |
C#中引用类型包括类、接口、委托、数组、字符串等。
数据存储:C#中值类型用于存储数据的值,而引用类型用于存储对实际数据的引用,即数据在堆内存中的存储位置编号(存储单元地址)。
类实例化对象时,CLR会根据其结构在堆内存中分配一片空间,对象的成员变量也存储在其中,基本类型和引用类型的成员变量都在这个对象的空间中,作为一个整体存储在堆。所有的对象都存储自己的非静态变量数据。而类的方法被所有的对象共享,方法不占据内存,只有在被调用时候才进栈。
三 代码运行过程内存分析
class People { private string name; private int age; public People(string name, int age) { this.name = name; this.age = age; } public void print() { Console.WriteLine("name:"+this.name+"age:"+this.age); } } class Program { public static void Main(string[] args) { People p = new People("小明", 5); p.print(); } } |
代码运行过程:
- 执行程序,加载程序进内存
- 主函数Main方法进栈
- 构造函数People("小明", 5)进栈,执行构造函数,在堆内存中分配一片区域(假设区域内存存储单元地址为0Xf001)用于存储对象值,对象成员变量初始时候name指向null引用指针,age=0.赋值后,name=”小明”,age=5.
- 构造函数出栈,继续执行Main方法
- 声明引用类型数据People p,将内存存储单元地址0Xf001赋值给p.
- p指向的对象的print()方法进栈,执行print()方法,print()出栈。
- 主函数出栈,程序结束。
备注:关于值类型与引用类型的数据内存回收请查看“第3篇 构造函数与析构函数”中相关内容。