2015-01-28 7 views
14

विजुअल स्टूडियो 2013 प्रदर्शन विज़ार्ड के साथ मेरे कोड के .NET स्मृति आवंटन का विश्लेषण करते समय मैंने कई बाइट आवंटित करने के लिए एक निश्चित फ़ंक्शन देखा (क्योंकि इसे बड़े लूप में कहा जाता है)। लेकिन प्रोफाइलिंग रिपोर्ट में हाइलाइट किए गए फ़ंक्शन को देखते हुए मुझे समझ में नहीं आया कि यह किसी भी स्मृति को आवंटित क्यों कर रहा था।स्मृति निष्पादन के कारण गैर निष्पादन linq सी #

बेहतर समझने के लिए कि क्या हुआ, मैंने आवंटन के कारण कोड को अलग कर दिया। यह नीचे LinqAllocationTester वर्ग के समान था।

एक बार जब मैंने उस फ़ंक्शन में LINQ कोड पर टिप्पणी की, जिसे परीक्षण कोड पथ में कभी भी निष्पादित नहीं किया गया था, अब कोई स्मृति आवंटित नहीं की गई थी। NonLinqAllocationTester कक्षा इस व्यवहार का अनुकरण करती है। सामान्य लूप के साथ LINQ कोड को प्रतिस्थापित करने से स्मृति आवंटन भी नहीं हो जाता है।

यदि मैं नीचे दिए गए टेस्ट कोड पर .NET स्मृति आवंटन परीक्षण चलाता हूं तो यह दिखाता है कि LinqAllocationTester 100.000 आवंटन (1 प्रति कॉल) का कारण बनता है, जबकि NonLinqAllocationTester में कोई नहीं है। ध्यान दें कि लिनक का उपयोग हमेशा झूठा होता है, इसलिए LINQ कोड को वास्तव में कभी भी निष्पादित नहीं किया जा रहा है।

Function Name     | Inclusive | Exclusive | Inclusive | Exclusive 
           | Allocations | Allocations | Bytes  | Bytes 
------------------------------------------------------------------------------------- 
LinqAllocationTester.Test(int32) |  100.000 |  100.000 | 1.200.000 | 1.200.000 
Program.Main(string[])   |  100.000 |   0 | 1.200.000 |   0 

तो क्यों करता है गैर LINQ कोड कारण स्मृति आवंटन को क्रियान्वित? और क्या LINQ फ़ंक्शंस से बचने के अलावा इसे रोकने का कोई तरीका है?

class Program { 
    static void Main(string[] args) { 
     List<int> values = new List<int>() { 1, 2, 3, 4 }; 
     LinqAllocationTester linqTester = new LinqAllocationTester(false, values); 
     NonLinqAllocationTester nonLinqTester = new NonLinqAllocationTester(false, values); 

     for (int i = 0; i < 100000; i++) { 
      linqTester.MaxDifference(i); 
     } 

     for (int i = 0; i < 100000; i++) { 
      nonLinqTester.MaxDifference(i); 
     } 
    } 
} 

internal class LinqAllocationTester { 
    private bool useLinq; 
    private List<int> values; 

    public LinqAllocationTester(bool useLinq, List<int> values) { 
     this.useLinq = useLinq; 
     this.values = values; 
    } 

    public int MaxDifference(int value) { 
     if (useLinq) { 
      return values.Max(x => Math.Abs(value - x)); 
     } else { 
      int maxDifference = int.MinValue; 
      foreach (int value2 in values) { 
       maxDifference = Math.Max(maxDifference, Math.Abs(value - value2)); 
      } 
      return maxDifference; 
     } 
    } 
} 

internal class NonLinqAllocationTester { 
    private bool useLinq; 
    private List<int> values; 

    public NonLinqAllocationTester(bool useLinq, List<int> values) { 
     this.useLinq = useLinq; 
     this.values = values; 
    } 

    public int MaxDifference(int value) { 
     if (useLinq) { 
      return 0; 
     } else { 
      int maxDifference = int.MinValue; 
      foreach (int value2 in values) { 
       maxDifference = Math.Max(maxDifference, Math.Abs(value - value2)); 
      } 
      return maxDifference; 
     } 
    } 
} 

उत्तर

7

आप को देखने के लिए कि LINQ अभिव्यक्ति के लिए DisplayClass पहले अगर-शाखा के बाहर विधि की शुरुआत में प्रारंभ हो जाएगा उत्पन्न आईएल में पर नज़र कर सकते हैं। ऐसा इसलिए है क्योंकि यह विधि की शुरुआत में लैम्ब्डा अभिव्यक्ति के बंद होने का अनुमान लगा रहा है (जहां मूल्य पहले दिखाई देता है)।

आईएल:

IL_0000: ldnull 
IL_0001: stloc.2 
IL_0002: newobj instance void ConsoleApplication2.LinqAllocationTester/'<>c__DisplayClass2'::.ctor() 
IL_0007: stloc.3 
IL_0008: ldloc.3 
IL_0009: ldarg.1 
IL_000a: stfld int32 ConsoleApplication2.LinqAllocationTester/'<>c__DisplayClass2'::'value' 
IL_000f: nop 
IL_0010: ldarg.0 
IL_0011: ldfld bool ConsoleApplication2.LinqAllocationTester::useLinq 
IL_0016: ldc.i4.0 
IL_0017: ceq 
IL_0019: stloc.s CS$4$0001 
IL_001b: ldloc.s CS$4$0001 
IL_001d: brtrue.s IL_0042 

आप इस तरह एक संकरा scoped चर करने के लिए अपने मान की प्रतिलिपि हैं:

if (useLinq) 
{ 
    int value2 = value; 
    return values.Max(x => Math.Abs(value2 - x)); 
} 

अतिरिक्त आवंटन अब और नहीं होना चाहिए।

संबंधित मुद्दे