C# 语言的数据类型分为值类型和引用类型。
值类型(Value types):
值类型包括结构体和枚举类型。结构体包括整数、小数,布尔值等。
值类型的默认值一般为 0,例如整数和小数的默认值都是 0,枚举类型的默认值也为 0, char 的默认值为 ‘\0’。
值类型的内存分配
三种情况:
值类型作为局部变量。
普通的值类型总是分配在栈上。例如以最简单的 int 为例,int a=1 意味着我们在栈上开辟了一块空间存储这个值类型。
using System;
namespace _20201102
{
class Program
{
static void Main()
{
int a = 1;
int b = a;
a = 2;
Console.WriteLine("a=" + a);
Console.WriteLine("b=" + b);
Console.ReadKey();
}
}
}
输出结果:
通俗的说:给a在栈中开辟一块空间,存入1,给b在栈中开辟一块空间存入和a相同的值1,然后修改a的值为2,此时b不变。
值类型作为引用类型的成员。
如果值类型为引用类型的成员,则遵从引用类型的内存分配和复制方式
public class A
{
public int m;
public string n;
}
var a = new A();
a.m = 1;
a.n = "hey";
此时m和n都存储在堆中,a在栈中存储了m和n的引用。
值类型中包含引用类型。
如果一个结构体中包含了引用类型(例如结构体),例如包含了一个字符串或者类,则它引用类型的那部分会遵从引用类型创建的内存分配,值类型的那部分则遵从值类型创建的内存分配。
public class A
{
public int m;
public string n;
}
public struct B
{
public Class a
public double c
}
var b = new B();
b.c = 1.1;
var a = new A();
a.m = 1;
a.n = "hey";
那么a的数据m和n存储在堆中,a的引用存储在栈中,c存储在栈中
值类型都分配在栈上,引用类型都分配在堆上?
大多数情况是的,三种情况例外:
1.结构体如果含有引用类型成员,则该成员也会牵扯到堆的分配。就是刚才说过的情况
2.静态类型,如果一个变量是静态的,则无论它是什么类型,都会分配在加载堆上。
3.局部变量被捕获升级为密封类。
值类型总是分配在它声明的地方:作为字段时,跟随其所属的变量(实 例)存储;作为局部变量时,存储在栈上。(栈的内存是自动释放的,堆内存是.NET中会由GC来自动释放)
值类型笔记参考于:
C#/.NET值类型
菜鸟教程
C#详解值类型和引用类型区别
引用类型(Reference types):
引用类型包括类、接口、数组、委托、字符串等。
引用类型不包含存储在变量中的实际数据,但它们包含对变量的引用。
换句话说,它们指的是一个内存位置。使用多个变量时,引用类型可以指向一个内存位置。如果内存位置的数据是由一个变量改变的,其他变量会自动反映这种值的变化。内置的 引用类型有:object、dynamic 和 string。
static void Main()
{
string a = "abc";
string b = a;
a = "123";
Console.WriteLine("a=" + a);//123
Console.WriteLine("b=" + b);//abc
Console.ReadKey();
}
以上代码看起来string很像值类型,但是实际情况是:
string a = “abc”; 在栈中首先给a存储了堆中abc的引用
string b = a; 将abc的引用同时给栈上的b
a = “123”; a将abc的引用改成123的引用,此时a指向123,b仍指向abc