尽管无法在运行时执行此lambda闭包,但为什么会生成垃圾呢?

Xarbrough

我注意到以下代码生成堆分配,该分配在某个时候触发垃圾收集器,我想知道为什么会这样,以及如何避免这种情况:

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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么此代码在运行时会生成很大的可执行文件(大约81M)?

为什么 shell 命令会生成运行时错误 53?

为什么此C程序在运行时引发分段错误?

为什么此Typescript接口在运行时捆绑中导致空异常?

为什么在运行时重新定义的此方法不保留其值?

为什么此代码编译并在执行时给出运行时错误

Windows在运行时删除make可执行文件。为什么?

在运行时生成可执行jar

为什么我的全局extern lambda变量在运行时未初始化?

空指针运行时异常erorr,但为什么呢?

为什么不能在运行时安全地生成fmt :: Arguments?

为什么自动绑定的props在运行时通过propTypes生成警告消息?

为什么我的 swig 生成的 tcl 代码在运行时缺少方法?

Eclipse在运行时不会生成新的类文件

为什么当我从 jaxws-maven-plugin 生成 wsdl 类时,由于缺少 ProviderImpl,它们无法在运行时运行?

为什么在运行时无法访问Eclipse插件的类?

为什么在运行时无法调整大小/移动已挂载(非逻辑)分区的大小?

如何在运行时打印函数,变量名,闭包等的文本?

为什么此函数应用程序会在purescript中生成运行时错误?

为什么此代码使用UndecidableInstances进行编译,然后生成运行时无限循环?

为什么包对象中类型的类名称在运行时类名称中包含“包”?

为什么我的 vba 脚本在逐行执行时(在调试中)有效,但在运行时无效?

为什么@Nonnull标注在运行时检查?

为什么@Nonnull标注在运行时检查?

为什么该程序在运行时出现错误

为什么这个简单的strcat在运行时崩溃?

为什么在运行时未实现重载?

为什么 Android 视图值在运行时不同?

为什么此 VBA 代码运行时间过长?