簡體   English   中英

即使此 Func<> 變量為空,是什么導致內存分配?

[英]What causes a memory allocation even when this Func<> variable is null?

使用 BenchmarkDotNet 的內存診斷程序,即使使用parameters = null調用此代碼,它似乎也分配了 12B:

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 實例無效 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);
}

這是基准測試結果:

方法 意思是 錯誤 標准差 0代 已分配
Log_WithInfra_ExtensionMethodDirect_NoParameters 8.441 納秒 18.732 納秒 1.027 納秒 0.0023 12 乙

這很愚蠢,對我的用例來說並不重要,但它讓我發瘋。

問題是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);
   }

我試過這段代碼:

    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)
        {
            var capturable = parameters;
            function = () => capturable;
        }

        logger.Usage(logLevel, area, operation, function);
    }

它會導致 44B 的分配。

我錯過了什么?

方法 意思是 錯誤 標准差 0代 已分配
Log_WithInfra_ExtensionMethodDirect_NoParameters 11.83 納秒 4.657 納秒 0.255 納秒 0.0084 44乙

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM