2015-05-08 19 views
5

yapar nerede.Sonra bellek bültenleri almaz <code>where predicate</code> içeride dışarıda başvuru eklerseniz yüklemleri değil bültenleri bellek

Böyle bir where predicate yazarsanız en Sonra bir List<object> var diyelim:

List<object> myList = new List<object>(); 
    ... 
    myList.add(object); 
    ... 

    Expression<Func<object,bool>> predicate = p => myList.Contains(p); 

Ben myList = null veya predicate = null, bu belleği serbest değil yapmak bile edin.

Ben List<object> itemsourceDataGrid binded var. Ayrıca DataGrid, DataGrid null atıyor, onu ItemSource null yapmak. . Bu sorunu ANTS Memory Profiler 7.4 ile de analiz ettim. Ayrıca çünkü wherepredicate ait bu referansa sahip olduğunu bana gösteriyor.

ben dispose() böyle benim wherepredicate değiştirirseniz, o zaman hafıza serbest oluyor. WherePredicate referansı kaldırılması anlamına gelir

Expression<Func<object,bool>> predicate = p => p.id == 0; 

.

+1

Lütfen sorunu gösteren kısa ama eksiksiz bir programı gösterin. Şüpheliyim * kullandığınız profilerle ilgili bir sorun olabilir ya da yanlış anlıyor olabilirsiniz. –

+2

(Açıklamak için isteklere cevap vermeyecekseniz bir soru üzerine bir ödül koymanın pek bir anlamı yok ...) –

+0

Hey john ... Projemde nasıl kullanıldığımı merak ettim ... Bu konuyu Ants bellek profiler ile analiz ettik .. Ama bana anonim tipler gösterir ... –

cevap

7

Mmmh ... ilginç ... hatta Expression<> neden kapanması ... ben bilmiyordum ...

Sonuç: yüklem myList

başvuru yok Ben anlatacağım:

private static bool IsDebug() 
{ 
    // Taken from http://stackoverflow.com/questions/2104099/c-sharp-if-then-directives-for-debug-vs-release 
    object[] customAttributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(DebuggableAttribute), false); 

    if ((customAttributes != null) && (customAttributes.Length == 1)) 
    { 
     DebuggableAttribute attribute = customAttributes[0] as DebuggableAttribute; 
     return (attribute.IsJITOptimizerDisabled && attribute.IsJITTrackingEnabled); 
    } 

    return false; 
} 

static void Main(string[] args) 
{ 
    // Check x86 or x64 
    Console.WriteLine(IntPtr.Size == 4 ? "x86" : "x64"); 

    // Check Debug/Release 
    Console.WriteLine(IsDebug() ? "Debug, USELESS BENCHMARK" : "Release"); 

    // Check if debugger is attached 
    Console.WriteLine(System.Diagnostics.Debugger.IsAttached ? "Debugger attached, USELESS BENCHMARK!" : "Debugger not attached"); 

    Console.WriteLine(); 

    { 
     long memory = GC.GetTotalMemory(true); 

     // A big array, big enough that we can see its allocation in 
     // memory 
     byte[] buffer = new byte[10000000]; 

     Console.WriteLine("Just allocated the array: {0}", GC.GetTotalMemory(true) - memory); 

     // A List<>, containing a reference to the buffer 
     List<object> myList = new List<object>(); 
     myList.Add(buffer); 

     Console.WriteLine("Added to the List<>: {0}", GC.GetTotalMemory(true) - memory); 

     // We want to be sure that buffer is referenced at least up to 
     // this point 
     GC.KeepAlive(buffer); 

     // But clearly setting buffer = null is useless, because the 
     // List<> has anothe reference 
     buffer = null; 
     Console.WriteLine("buffer = null: {0}", GC.GetTotalMemory(true) - memory); 

     // If I Clear() the List<>, the last reference to the buffer 
     // is removed, and now the buffer can be freed 
     myList.Clear(); 
     Console.WriteLine("myList.Clear(): {0}", GC.GetTotalMemory(true) - memory); 

     GC.KeepAlive(myList); 
    } 

    Console.WriteLine(); 
    GC.Collect(); 

    { 
     long memory = GC.GetTotalMemory(true); 

     // A big array, big enough that we can see its allocation in 
     // memory 
     byte[] buffer = new byte[10000000]; 

     Console.WriteLine("Just allocated the array: {0}", GC.GetTotalMemory(true) - memory); 

     // A List<>, containing a reference to the buffer 
     List<object> myList = new List<object>(); 
     myList.Add(buffer); 

     Console.WriteLine("Added to the List<>: {0}", GC.GetTotalMemory(true) - memory); 

     // We want to be sure that buffer is referenced at least up to 
     // this point 
     GC.KeepAlive(buffer); 

     // But clearly setting buffer = null is useless, because the 
     // List<> has another reference 
     buffer = null; 
     Console.WriteLine("buffer = null: {0}", GC.GetTotalMemory(true) - memory); 

     // We want to be sure that the List<> is referenced at least 
     // up to this point 
     GC.KeepAlive(myList); 

     // If I set to null myList, the last reference to myList 
     // and to buffer are removed 
     myList = null; 
     Console.WriteLine("myList = null: {0}", GC.GetTotalMemory(true) - memory); 
    } 

    Console.WriteLine(); 
    GC.Collect(); 

    { 
     long memory = GC.GetTotalMemory(true); 

     // A big array, big enough that we can see its allocation in 
     // memory 
     byte[] buffer = new byte[10000000]; 

     Console.WriteLine("Just allocated the array: {0}", GC.GetTotalMemory(true) - memory); 

     // A List<>, containing a reference to the buffer 
     List<object> myList = new List<object>(); 
     myList.Add(buffer); 

     Console.WriteLine("Added to the List<>: {0}", GC.GetTotalMemory(true) - memory); 

     // A predicate, containing a reference to myList 
     Expression<Func<object, bool>> predicate1 = p => myList.Contains(p); 
     Console.WriteLine("Created a predicate p => myList.Contains(p): {0}", GC.GetTotalMemory(true) - memory); 

     // A second predicate, **not** containing a reference to 
     // myList 
     Expression<Func<object, bool>> predicate2 = p => p.GetHashCode() == 0; 
     Console.WriteLine("Created a predicate p => p.GetHashCode() == 0: {0}", GC.GetTotalMemory(true) - memory); 

     // We want to be sure that buffer is referenced at least up to 
     // this point 
     GC.KeepAlive(buffer); 

     // But clearly setting buffer = null is useless, because the 
     // List<> has another reference 
     buffer = null; 
     Console.WriteLine("buffer = null: {0}", GC.GetTotalMemory(true) - memory); 

     // We want to be sure that the List<> is referenced at least 
     // up to this point 
     GC.KeepAlive(myList); 

     // If I set to null myList, an interesting thing happens: the 
     // memory is freed, even if the predicate1 is still alive! 
     myList = null; 
     Console.WriteLine("myList = null: {0}", GC.GetTotalMemory(true) - memory); 

     // We want to be sure that the predicates are referenced at 
     // least up to this point 
     GC.KeepAlive(predicate1); 
     GC.KeepAlive(predicate2); 

     try 
     { 
      // We compile the predicate1 
      Func<object, bool> fn = predicate1.Compile(); 
      // And execute it! 
      fn(5); 
     } 
     catch (NullReferenceException) 
     { 
      Console.WriteLine("predicate1 is 'pointing' to a null myList"); 
     } 
    } 
} 

Bu üç bölümden örnek testtir: temel nokta büyük byte[] dizi tahsis edilir olması ve tahsis ne kadar bellek kontrol yoluyla biz dizi kontrol hala bir şekilde tahsis edilir. kod hata ayıklayıcı (CTRL + F5) olmadan yayın modunda çalıştırıldığında çok önemlidir. Eğer bunu yapmazsanız programı

ilk iki "bölümlerini" başladığında, bir uyarı alırsınız bir List<> başvurduğu öğeleri (şimdiye byte[] yılında "canlı" tutmak olmadığını göstermek için sadece Bu durumda) ve GC byte[] toplamak sağlar ing List<> veya .Clear() kurtararak. hem List<> ve Expression<> ... Hem byte[] bir başvuru tutmak gibi görünüyor vardır, ancak bu bir yanılsama:

üçüncü bölümü daha ilginç. Yazılı olarak Expression<>, derleyicinin myList<> değişkeninin etrafında bir "kapanma" oluşturmasına neden olur. ILSpy kullanma bunu görmek oldukça kolaydır:

Program.<>c__DisplayClassb <>c__DisplayClassb = new Program.<>c__DisplayClassb(); 
<>c__DisplayClassb.myList = new List<object>(); 
<>c__DisplayClassb.myList.Add(buffer3); 

ParameterExpression parameterExpression = Expression.Parameter(typeof(object), "p"); 
Expression<Func<object, bool>> predicate = Expression.Lambda<Func<object, bool>>(Expression.Call(Expression.Field(Expression.Constant(<>c__DisplayClassb), fieldof(Program.<>c__DisplayClassb.myList)), methodof(List<object>.Contains(!0)), new Expression[] 
{ 
    parameterExpression 
}), new ParameterExpression[] 
{ 
    parameterExpression 
}); 

bir gizli (Eğer ILSpy yoksa daha basit ve hızlı numune için çevrimiçi derleyici TryRoslyn tarafından üretilen koda bir göz atabilirsiniz) myList alanı ile derleyici tarafından <>c__DisplayClassb sınıfı oluşturulur. Dolayısıyla, bir "yerel" değişkeni myList yerine, yöntem myList numaralı bir alana sahip <>c__DisplayClassb yerel değişkenine sahiptir. predicate1, myList referansını doğrudan tutmaz, ancak <>c__DisplayClassb değişkenine bir referansı vardır (bkz. Expression.Constant(<>c__DisplayClassb)?), Bu yüzden

<>c__DisplayClassb.myList = null; 

predicate1 hala <>c__DisplayClassb referansı olan, ancak <>c__DisplayClassb.myListnull, yani myList için daha fazla referanslar olduğunda.

+0

Evet, listeyi temizlemeyi denedim ama işe yaramayacak ... –

+0

@AmolBavannavar - İşe yaramadığını nereden biliyorsun? –

+0

@ErnodeWeerd Bunu Analizörle analiz ettim ... –