private void Check_ReuseCoroutinue() { Profiler.BeginSample("Check_ReuseCoroutinue"); Profiler.BeginSample("1"); if (_testingCor1 == null) { _testingCor1 = StartCoroutine(TestingCor1()); } Profiler.EndSample(); Profiler.BeginSample("2"); if (_testingCor2 == null) { _testingCor2 = TestingCor2(); } if (_testingCor2 != null) { if (_testingCor2.MoveNext()) { int v = (int)_testingCor2.Current; } else { //_testingCor2.Reset(); // C# 语法糖生产的没有 Reset 实现,这里会报错 } } Profiler.EndSample(); Profiler.BeginSample("3"); if (_testingCor3 == null) { _testingCor3 = new UnityCoroutineInst_NoBoxingOperates(); } if (_testingCor3 != null) { if (_testingCor3.MoveNext()) { int v = _testingCor3.Current; } else { _testingCor3.Reset(); // 我们自己实现的 Cortoutine 就可以随心所欲的 Reset,因为自己实现了接口,这样就不用重新 new 一个协程管理对象,也就没有 GC 了 } } Profiler.EndSample(); Profiler.EndSample(); // Profile 结果 // 1、2 方式都因为 C# 语法糖内部实际 new 了一个类似 UnityCoroutineInst_NoBoxingOperates 的类来分状态处理,所以每次获取一个 Enumerator 时,都会有 GC // 3 方式虽然我们也实现了对应的 IEnumerator,但是我们自己可实现对 Reset 接口的处理,所以不用重新 new,因此只有第一次 new 有 GC // 因此,没事不要频繁的 StartCortoutine ,因为有 GC // 尽可能使用 Update 函数来处理 }
private void Check_Enumerator() { Profiler.BeginSample("Check_Enumerator"); Profiler.BeginSample("1"); if (enumerator_first_run) { enumerator = GetEnumerator(); } if (enumerator != null) { if (enumerator.MoveNext()) { int v = enumerator.Current; } else { enumerator = null; } } Profiler.EndSample(); Profiler.BeginSample("2"); if (enumerator_first_run) { StartCoroutine(GetEnumerator()); } Profiler.EndSample(); Profiler.BeginSample("3"); if (enumerator_first_run) { cor_inst_have_boxing = new UnityCoroutineInst_HaveBoxOperates(); } if (cor_inst_have_boxing != null) { if (cor_inst_have_boxing.MoveNext()) { int v = enumerator.Current; } else { cor_inst_have_boxing = null; } } Profiler.EndSample(); Profiler.BeginSample("4"); if (enumerator_first_run) { cor_inst_no_boxing = new UnityCoroutineInst_NoBoxingOperates(); } if (cor_inst_no_boxing != null) { if (cor_inst_no_boxing.MoveNext()) { int v = enumerator.Current; } else { cor_inst_no_boxing.Dispose(); cor_inst_no_boxing = null; } } Profiler.EndSample(); Profiler.EndSample(); enumerator_first_run = false; // Profile 结果 // IEnumerator + yield 本质上就是 C# 编译器的语法糖,会生产一个状态机,对不同逻辑的 yield 设置到不一样的 swtich(state) 的 case 分支上执行对应的逻辑 // 所以在获取 IEnumerator 实例的瞬间就 new 了一个对象来构造状态信息,这回导致 GC 的 // 所以控制好获取 IEnumerator 的次数,和帧频调用率 }