C#值类型和引用类型的区别-程序验证
区别
值类型分配在栈上(如果不在栈帧当中声明),如果是类的属性、数组、被装箱、放在闭包中那就是在堆上。
引用类型分配在堆上,栈中存的是引用变量,引用变量的值是堆上的地址。
GC 只管堆,不管栈
栈:自动释放
堆:GC 回收
值类型
数据直接存在声明的位置
方法内 → 栈
类 / 数组 / 装箱 → 堆
和大小无关!
引用类型
真实数据 → 永远在堆
栈上只存引用(地址)
引用变量 = 指向堆的指针
static void Main()
{
// 值类型
int a = 100;
cwl($"{nameof(a)} 栈地址: {(long)&a:X}");
// 引用类型变量(栈)
string str = "hello";
cwl($"str 变量栈地址: {(long)&str:X}");
// 引用类型对象(堆)
fixed (char* p = str)
{
cwl($"str 堆真实地址: {(long)p:X}");
}
// 栈里存的就是堆地址
long* pStr = (long*)&str;
cwl($"栈中存储的堆地址: {*pStr:X}");
}
static void cwl(string msg) => Console.WriteLine(msg);
}
输出结果

仅从地址是无法判断的 但是分配在栈中的地址一般是相邻几个字节的
而分配在堆中的地址有跳变、巨大、不连续的特征。
结果分析
栈上
43A5D7EE00:str 变量本身的地址(栈),里面存着 21180101DB0(堆对象地址)
43A5D7EE08:int a 变量的地址(栈),里面存着 100 这个值
堆上
21180101DB0:string 对象的起始地址(对象头、长度信息)
21180101DBC:string 里 char 数组的起始地址(也就是你用 fixed 拿到的地址)
浙公网安备 33010602011771号