c# - 即使此 Func<> 变量为空,是什么导致内存分配?

标签 c# .net memory-management allocation benchmarkdotnet

使用 BenchmarkDotNet 的内存诊断器,即使使用 parameters 调用,这段代码似乎也分配了 12B = null :

public static void Usage(this ILogger logger, LogLevel logLevel, string area, string operation, Dictionary<string, string> parameters)
{
    Func<Dictionary<string, string>> function = null;
    if (parameters != null)
    {
        function = new Func<Dictionary<string, string>>(() =>
        {
            return parameters;
        });
    }
    logger.Usage(logLevel, area, operation, function);
}

如果我删除对 function 的分配,分配降为 0。当我查看 IL 代码时,我可以看到以下几行:

IL_0000: newobj instance void MIT.Logging.Infrastructure.LoggerExtensions/'<>c__DisplayClass0_0'::.ctor()

IL_001f: newobj instance void class [mscorlib]System.Func`1<class [mscorlib]System.Collections.Generic.Dictionary`2<string, string>>::.ctor(object, native int)

第二行是有道理的,它应该是有条件的,在我的具体情况下,条件不满足。但是第一个我无法解释。

这是基准方法:

[Benchmark]
public void Log_WithInfra_ExtensionMethodDirect_NoParameters()
{
    LoggerExtensions.Usage(_logger, LogLevel.Information, LogAreas.MainApplication.AreaName, LogAreas.MainApplication.Operations.Operation0, null);
}

这是基准测试结果:

<表类="s-表"> <头> 方法 均值 错误 标准偏差 第 0 代 已分配 <正文> Log_WithInfra_ExtensionMethodDirect_NoParameters 8.441 纳秒 18.732 纳秒 1.027 纳秒 0.0023 12 B

这很愚蠢,它对我的​​用例来说并不那么重要,但它让我发疯。

最佳答案

问题是 parameters 的范围超出了条件的范围,因此捕获它的闭包是在顶层创建的。

将您的原始代码简化为此,例如:

public static void Usage(string area, string operation, Dictionary<string, string> parameters)
{
    Func<Dictionary<string, string>> function = null;

    if (parameters != null)
    {
        function = new Func<Dictionary<string, string>>(() =>
        {
            return parameters;
        });
    }
}

... C# 1.0 等效项如下所示:

   <>c__DisplayClass5_0 <>c__DisplayClass5_ = new <>c__DisplayClass5_0 ();
   <>c__DisplayClass5_.parameters = parameters;
   Func<Dictionary<string, string>> function = null;
   if (<>c__DisplayClass5_.parameters != null)
   {
        function = new Func<Dictionary<string, string>> (<>c__DisplayClass5_.<Usage>b__0);
   }

您可以看到闭包已创建,并且设置了它的属性,以便在函数的任何地方需要时都可以使用它。为避免在不满足您的条件时发生这种情况,请创建一个单独的变量,其范围限定为您的 if 条件。

public static void Usage(string area, string operation, Dictionary<string, string> parameters)
{
    Func<Dictionary<string, string>> function = null;

    if (parameters != null)
    {
        var capturable = parameters;
        function = new Func<Dictionary<string, string>>(() =>
        {
            return capturable;
        });
    }
}

这会将您的 C# 1.0 等效代码更改为:

   Func<Dictionary<string, string>> function = null;
   if (parameters != null)
   {
        <>c__DisplayClass5_0 <>c__DisplayClass5_ = new <>c__DisplayClass5_0 ();
        <>c__DisplayClass5_.capturable = parameters;
        function = new Func<Dictionary<string, string>> (<>c__DisplayClass5_.<Usage>b__0);
   }

关于c# - 即使此 Func<> 变量为空,是什么导致内存分配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72903359/

相关文章:

c# - 如何测试WPF表单?

c# - 在 ASP .NET MVC 应用程序中创建用户角色时出现错误

asp.net - ASP.NET Core 中的 HttpResponse.Filter 等效项

.net - 父子数据的 xslt 递归模板

c# - 我如何验证 wpf 绑定(bind)是否会转到真实属性?

python - 压缩由0和1组成的长向量

c# - 从 ASP.NET 网站获取 IIS 站点名称

c++ - 将内存池与需要对齐内存的 cpu 一起使用是个好主意吗?

java - java应用程序可以分配比jvm启动参数指定的更多的内存吗?

c# - 在 flowLayout 中的控件之间设置更多空间