C# 垃圾回收
C 使用 malloc() 进行动态内存空间分配,当那一部分空间不被需要时就得 free() 手动释放。如果没有进行释放,那么就要等程序结束,在此期间就造成了内存泄漏。为了避免这些情况,现代语言有一些自动回收的特性(Garbage Collection)。为了便于以后 s&box 的进一步开发,最近正在学习一点 C#。它当然有一套 GC 机制。
GC 的条件
内存不足。
手动调用了
GC.Collect方法:
for (int i = 0; i < 10000; i++)
{
var temp = new object();
}
// 强制触发 GC
GC.Collect();
GC 的机制
GC 先默认堆中的所有对象都是可以回收的,然后再标记哪些对象被引用(它们是可达/活动的),然后清除掉不可达的对象。
GC.Collect() 里面可以有参数,比如 0 就对应 Gen 0。这是因为 Generational GC 的关系。
| Gen 0 | Gen 1 | Gen 2 |
|---|---|---|
| 新创建的(小) | Gen 0 回收后存活的 | 长期存活的(大) |
当 Gen 0 堆中的内存达到某个阈值,则触发 Gen 0 GC,剩下的存活对象进入 Gen 1;如果 Gen 1 的也达到阈值,则触发 Gen 1 GC,并且同时 Gen 0 中的也再次回收一遍,存活的对象全部放入 Gen 2 的堆内存空间;Gen 2 GC 则同时回收 0, 1, 2 三代的。
问题
GC 需要时间
假设在一个大型开放世界游戏内,玩家突然从一个点跑到距离很远的另一个点,那么旧的点周围的资产必须被卸载掉,否则会爆内存。
如果在这期间进行 GC,游戏将面临十分严重的卡顿。解决方法就是黑屏加载,但是这相当影响观感,所以非传统的流式资产传输(Streaming Assets)应运而生,比如在《荒野大镖客:救赎 2》这样的游戏里,使用外挂进行超速飞行,很难感觉到卡顿。
GC 不能释放所有资源
GC 并不能释放非托管的资源,因为回收机制的一个前提就是它要回收的内存被分配在托管堆上。