【Unity】【CSharp】堆与栈


值类型和引用类型

值类型和引用类型的存储方式

  • 引用类型:引用类型存储在堆中。类型实例化的时候,会在堆中开辟一部分空间存储类的实例。类对象的引用还是存储在栈中。
  • 值类型:值类型总是分配在它声明的地方,做为局部变量时,存储在栈上;类对象的字段时,则跟随此类存储在堆中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Program
{
static void Main(string[] args)
{
// s:对象的引用[存储在栈中]
//new Student()[对象存储在堆中]
Student s = new Student(); // 引用类型

// 局部变量[存储在栈中]
int a = 0; // 值类型
}
}

internal class Student
{
// 类的字段[跟随此类存储在堆中]
public int Age = 0;// 值类型
}

值类型和引用类型的区别

  • 引用类型和值类型都继承自Systerm.Object类。不同之处,值类型则是继承Systerm.Object的子类Systerm.ValueType类,而几乎所有的引用类型都是直接从Systerm.Object继承。
  • 我们在给引用类型的变量赋值的时候,其实只是赋值了对象的引用;而给值类型变量赋值的时候是创建了一个副本(副本不明白?说通俗点,就是克隆了一个变量,即python中的深拷贝)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Program
{
static void Main(string[] args)
{
// 值类型复制
int a = 0;
int a2 = a;
a2 = 10;
Consle.WriteLine(a); // 输出:0

// 引用类型复制
Student s = new Student();
s.Age = 10;
Student s2 = s; // 给引用类型的变量赋值的时候,其实只是赋值了对象的引用
s2.Age = 20;
Console.WriteLine(s.Age); // 输出:20
}
}

internal class Student
{
public int Age = 0;
}

值类型和引用类型的内存分配情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Program
{
static void Main(string[] args)
{
int i = 10; // int类型在栈中占了四个字节(栈中地址:673EED8)
Student s = new Student(); // 一个对象的引用在栈中占四个字节
long j = 20; // long类型栈中占八个字节(栈中地址:673EECC)
}
}

internal class Student
{
public int Age1 = 10;
public int Age2 = 20;
}

  • 栈的结构是后进先出,也就是说:变量j的生命周期在变量s之前结束,变量s的生命周期在变量i之前结束,

  • 栈地址从高往底分配

  • 类型的引用也存储在栈中


堆与栈的详细介绍

搞不明白堆和栈的叫法

堆:在c里面叫堆,在c#里面其实叫托管堆。

栈:就是堆栈,因为和堆一起叫着别扭,就简称栈了。

托管堆

托管堆不同于堆,它是由CLR(公共语言运行库(Common Language Runtime))管理,当堆中满了之后,会自动清理堆中的垃圾。所以,做为.net开发,我们不需要关心内存释放的问题。

搞不清楚内存堆栈与数据结构堆栈

  • 数据结构堆栈:是一种后进先出的数据结构,它是一个概念,图4-1中可以看出,栈是一种后进先出的数据结构。
  • 内存堆栈:存在内存中的两个存储区(堆区,栈区)。
    • 栈区:存放函数的参数、局部变量、返回数据等值,由编译器自动释放
    • 堆区:存放着引用类型的对象,由CLR释放

引用

C#堆与栈