一、直观比较

值类型 引用类型
继承父类 System.ValueType,System.ValueType继承System.Object System.Object
内存存放位置
大小 每个类型固定大小 不固定大小
回收时机 操作系统控制,作用域结束 GC控制
是否密封 不是
比较Equals 重写了Equals,比较的是内容数值 比较的是内存地址是否相同

二、(特殊)String

String是引用类型,但是实际使用起来还是值类型。

String的不变性

string 对象称为不可变的(只读),因为一旦创建了该对象,就不能修改该对象的值。有的时候看来似乎修改了,实际是string经过了特殊处理,每次改变值时都会建立一个新的string对象,变量会指向这个新的对象,而原来的还是指向原来的对象,所以不会改变。这也是string效率低下的原因。如果经常改变string的值则应该使用StringBuilder而不使用string。

String是引用类型,只是编译器对其做了特殊处理。

三、装箱与拆箱

3.1装箱

值类型转化为引用类型。

int number = 42; // 值类型
object boxedNumber = number; // 装箱

或将值类型作为参数传递给了参数为object的方法:

void PrintObject(object obj)
{
    Console.WriteLine(obj);
}

PrintObject(1); // 装箱发生

内存过程是:
1. 在堆上为装箱对象分配内存。

2. 将值类型的值分配到开辟的内存上。

3. 将开辟内存的引用放在栈中,通过引用访问这个对象。

3.2 拆箱

引用类型转化为值类型

object boxedNumber = 42; // 装箱
int number = (int)boxedNumber; // 拆箱

3.3 装箱与拆箱的缺点

1. 堆的内存分配比栈的慢,可能是因为堆的内存分配是相对随机的。

2. 在堆上分配内存会增加gc负担。

3. 拆箱时候要进行类型检查。

3.4 如何避免

使用泛型和合适的数据结构。比如List<T>而不是ArrayList。List支持泛型,ArrayList不支持。

ArrayList list = new ArrayList();
list.Add(number); // 装箱发生

四、垃圾回收GC

4.1 标记-压缩

通过一个图的数据结构来收集对象的根,这个根就是引用地址。可以理解为指向托管堆的关系线。当触发这个算法时,会检查图中的每个根是否可达,如果可达,则对其标记,然后在堆上找到剩余没有标记的对象进行删除。

4.2 分代

在主流 .NET/Mono/IL2CPP 里,托管 GC 的核心思想基本是:

  • 分代(Generational GC)

    • 堆被分成几代:Gen0、Gen1、Gen2(有的实现还有 LOH – Large Object Heap)。

    • 假设:“大部分对象都很快就死了,很少有对象活得特别久”(弱代假说)。

    • 所以会频繁地只扫描 Gen0,不总是全堆扫描。

  • 标记 – 清除 / 标记 – 压缩(Mark & Sweep / Mark & Compact)

    1. 从“根对象”(栈上的局部变量、静态变量等)出发,遍历可达对象并标记为 alive

    2. 其他没被标记到的就是“不可达(垃圾)”。

    3. 清理时:

      • 要么直接把这些垃圾块记成“空闲区”(Mark & Sweep);

      • 要么把活着的对象向一侧压缩,腾出连续空间(Mark & Compact),好处是减少碎片,但需要移动对象,更新引用。

大部分现代的 .NET GC 都是一个组合拳,比如:

  • 小对象:分代 + 标记压缩

  • 大对象:单独放一个堆(LOH),只做标记清除、减少移动

4.3 Unity的GC

5.x版本前不会分代和多线程。

当你用 IL2CPP(例如 iOS、安卓、微信小游戏经常用)时:

  • C# 编译成 C++,再用平台编译器编译,但托管堆仍然由 Unity 自己的 GC 管理

  • Unity 在 IL2CPP 下使用的是 自家的 Boehm 派生 / Unity GC,现在也支持 增量 GC

  • 算法思想同样是:

    • 标记-清除 / 标记-压缩 + 增量执行

    • 仍然是典型的 追踪式 GC(Tracing GC),不是引用计数。

Logo

这里是一个专注于游戏开发的社区,我们致力于为广大游戏爱好者提供一个良好的学习和交流平台。我们的专区包含了各大流行引擎的技术博文,涵盖了从入门到进阶的各个阶段,无论你是初学者还是资深开发者,都能在这里找到适合自己的内容。除此之外,我们还会不定期举办游戏开发相关的活动,让大家更好地交流互动。加入我们,一起探索游戏开发的奥秘吧!

更多推荐