我注意到以下代码生成堆分配,该分配在某个时候触发垃圾收集器,我想知道为什么会这样,以及如何避免这种情况:
private Dictionary<Type, Action> actionTable = new Dictionary<Type, Action>();
private void Update(int num)
{
Action action;
// if (!actionTable.TryGetValue(typeof(int), out action))
if (false)
{
action = () => Debug.Log(num);
actionTable.Add(typeof(int), action);
}
action?.Invoke();
}
我知道使用lambda之类的() => Debug.Log(num)
将生成一个小的帮助程序类(例如<> c__DisplayClass7_0)来保存局部变量。这就是为什么我要测试是否可以在字典中缓存此分配的原因。但是,我注意到,即使由于if语句从未到达lambda代码,对Update的调用也会导致分配。当我注释掉lambda时,分配从探查器中消失。我正在使用Unity Profiler工具(Unity游戏引擎中的性能报告工具),该工具在开发/调试模式下以每帧字节为单位显示此类分配。
我猜想编译器或JIT编译器会为方法范围的lambda生成辅助类,即使我不明白为什么这是理想的。
最后,是否有任何方法可以以这种方式缓存委托而无需分配和不强制调用代码提前缓存操作?(我确实知道,我也可以在客户端代码中分配一次操作,但是在此示例中,我严格希望实现某种自动缓存,因为我没有对客户端的完全控制权)。
免责声明:这主要是出于理论上的问题。我确实意识到,大多数应用程序都不会从像这样的微优化中受益。
我猜想编译器或JIT编译器会为方法范围的lambda生成辅助类,即使我不明白为什么这是理想的。
考虑在同一方法中有多个匿名方法和闭包的情况(足够普遍)。您是要为每个实例创建一个新实例,还是让它们都共享一个实例?他们和后者一起去了。两种方法都有优点和缺点。
最后,是否有任何方法可以以这种方式缓存委托而无需分配和不强制调用代码提前缓存操作?
只需将匿名方法移到其自己的方法中,以便在调用该方法时无条件创建匿名方法。
private void Update(int num)
{
Action action = null;
// if (!actionTable.TryGetValue(typeof(int), out action))
if (false)
{
Action CreateAction()
{
return () => Debug.Log(num);
}
action = CreateAction();
actionTable.Add(typeof(int), action);
}
action?.Invoke();
}
(我没有检查分配是否针对嵌套方法发生。如果是,请将其设置为非嵌套方法并传入int。)
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句